Python小白带小白初涉多进程

来源:互联网 发布:男士旅行包 知乎 编辑:程序博客网 时间:2024/04/28 08:45

Python 2.7
IDE Pycharm 5.0.3

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)
—抄自廖雪峰的Python教程,顺便推广一下,这个教程真心棒,非常棒,棒出声!

废话不多说,直接来个栗子压压惊

# -*- coding: utf-8 -*-from multiprocessing import Process, Queueimport os, time, random#程序不是从这里开始读的!!,不然q会一头雾水def write(q):    for put_value in range(5):        print 'Put %s to queue...' % put_value        q.put(put_value)#堆入Queue        time.sleep(random.random())#缓会,有点累def read(q):    while True:        try:            get_value = q.get(True,3)#get3秒还有没有            print 'Get %s from queue.' % get_value        except:            print '3 seconds check, the list is empty'            break#拜托拜托,先看这里,程序是从这里开始读的!#↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓if __name__ == '__main__':    q = Queue()  # 创建Queue,也就是实例化Queue这个类    pw = Process(target=write, args=(q,))    #实例化Process    pr = Process(target=read, args=(q,))    pw.start()  # 调用start方法,启动进程,写入数据    pr.start()  # 启动进程,读出数据    pw.join()  # 等待pw进程结束    #pr.terminate()  #  pr是死循环,结束不了,强行终止    pr.join()    print 'all process have benn done'
Put 0 to queue...Get 0 from queue.Put 1 to queue...Get 1 from queue.Put 2 to queue...Get 2 from queue.Put 3 to queue...Get 3 from queue.Put 4 to queue...Get 4 from queue.3 seconds check, the list is emptyall process have benn done

这个补上Queue这个类,参数默认

class multiprocessing.Queue([maxsize]) 

补上Process使用方法

class multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}) Process objects represent activity that is run in a separate process. The Process class has equivalents of all the methods of threading.Thread.The constructor should always be called with keyword arguments. group should always be None; it exists solely for compatibility with threading.Thread. target is the callable object to be invoked by the run() method. It defaults to None, meaning nothing is called. name is the process name. By default, a unique name is constructed of the formProcess-N1:N2:...:Nk‘ where N1,N2,...,Nk is a sequence of integers whose length is determined by the generation of the process. args is the argument tuple for the target invocation. kwargs is a dictionary of keyword arguments for the target invocation. By default, no arguments are passed to target.If a subclass overrides the constructor, it must make sure it invokes the base class constructor (Process.__init__()) before doing anything else to the process.

巴拉巴拉巴拉巴拉一堆,我打赌你没看完就拉下来了,,,,,有用的参数也就两个,一个target,一个args,target用来可调用的object,上述栗子就是write和read函数啦,而args这个自变量用来传递那个object中的参数,也就是q啦,而q又是实例化的Queue啦,里面堆的都是write写进去的东西,还有一点就是,传一个tuple的时候记得加逗号–规定

还有就是put和get方法了,这个没什么好说的,自己查下官方文档,put简单说就是把value放那个q里面啊,get当然里面你又不能挑值来读,你就只有乖乖的True,然后默默拿别人辛辛苦苦放进去的value,自己拿完如果不terminate的话,一直在查,有没有,有没有,这q里面还有没有东西,不行,我得再查一遍,再查一遍。。。而查一遍的时间用timeout定义,我直接用了try…except方法让它别太放肆,拿完东西就滚,哈哈。

Queue.put(item[, block[, timeout]]) Queue.get([block[, timeout]]) 

如果进程数太多了,我一个人根本搞不过来,怎么办呢,还好有进程池Pool这个好基友啊,简单来说,Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

下面我再举个栗子

#coding: utf-8from multiprocessing import Poolimport time,randomdef func(name):    print "begin: %s" % (name)    start = time.time()    time.sleep(random.random()*3)    end = time.time()    print '%s,花了我%0.2f秒'%(name,(end-start))if __name__ == "__main__":    p = Pool(processes=4)#实例化    for i in range(6):        args = "需要执行的第 %d 个进程" %(i)        p.apply_async(func, (args, ))  # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去    #args就是将要传递给func的参数name    print "我先来我先来~~~~诶?为啥我在开头?"    p.close()    p.join()  #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束    print "所有线程运行结束!"

然后是结果咯:

我先来我先来~~~~诶?为啥我在开头?begin: 需要执行的第 0 个进程begin: 需要执行的第 1 个进程begin: 需要执行的第 2 个进程begin: 需要执行的第 3 个进程需要执行的第 1 个进程,花了我0.29begin: 需要执行的第 4 个进程需要执行的第 4 个进程,花了我0.72begin: 需要执行的第 5 个进程需要执行的第 3 个进程,花了我1.03秒需要执行的第 2 个进程,花了我1.35秒需要执行的第 0 个进程,花了我1.37秒需要执行的第 5 个进程,花了我2.95秒所有线程运行结束!

一行行解释,因为使用了apply_async是非阻塞的,所以主程序会自己执行自己的,不管其他进程的执行,所以直接出来了呢(自己编的,以后填坑),之后设定了Pool(processes=4)也就是说,池的大小为4,最多能提供四个进程数,而我们要用的进程数设置为6个,所以后面两个轮不到了,只有等前面四个进程其中一个结束之后,赶紧抢一个进程名额,麻蛋,和抢车位一样。然后再等一个进程结束,再空出一个位置,然后再抢一个,可以看到,进程结束的时间是不一样的,因为采用了random函数。。。。。至此,pool这个应该入门了。多种进程池的使用请看这里-传送门

然后–补上一波apply_async()的官方文件,查询官方文件才是正统的方法啊,小白看这个有点困难,可以直接百度下这个方法,好吧,我也只是装x贴上的,实际上还是百度的0.0,apply_async()用来向进程池提交目标请求

apply_async(func[, args[, kwds[, callback]]]) A variant of the apply() method which returns a result object.If callback is specified then it should be a callable which accepts a single argument. When the result becomes ready callback is applied to it (unless the call failed). callback should complete immediately since otherwise the thread which handles the results will get blocked.

在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。


致谢

@转–python 之 多进程

1 0