前言
(1)python中与多进程相关的包是multiprocessing。
(2)multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Lock、Semaphore、Queue、Pipe、Pool等组件。
Process类
(1)multiprocessing包里有个Process类,用于创建进程对象来执行任务,Process类的API如下:
Process([group [, target [, name [, args [, kwargs]]]]])
①target参数表示Process类对象要执行的任务,传入的是方法的名字。
②args表示执行的任务的位置参数元组,也就是进程执行的方法的参数。要注意的是它是元组类型的。
③kwargs表示调用对象的字典。
④name是别名,相当于给这个进程取一个名字。
⑤group分组,实际并不适用。
(2)创建了Process对象后,使用start方法启动进程,进程开始执行任务。
(3)通过cpu_count方法获取当前机器的CPU核的数量。
(4)通过active_children方法获取目前所有的正在运行的进程。
(5)Process对象也包含了name和pid等数据成员表示进程的属性。
自定义进程类
(1)通过继承Process类可以自定义进程类,然后实现run方法让进程执行任务。
(2)我们可以把一些方法独立的写在每个类里封装好,等用的时候直接初始化一个类然后运行就可以了。
daemon属性
(1)设置daemon属性为True表示当父进程结束后子进程自动被终止。
(2)这样可以有效防止无控制地生成子进程。
join方法
(1)调用进程的join方法能够让父进程(主进程)等待子进程执行完毕后再结束。
Lock类
(1)多进程不可避免地会访问或使用相同的资源(临界资源),这时候需要我们实现进程间的“互斥”来保证资源的正确访问和使用。
(2)可以通过Lock类对象来实现“互斥“。在一个进程访问临界资源时,加锁,让其它想要访问这个资源的进程处于等待状态。等当前进程访问资源完毕后,释放锁,让其它进程竞争锁以访问资源。
(3)使用acquire方法获得锁,release方法释放锁,临界资源需要包含在这两个方法之间。
Semaphore类
(1)信号量(semaphore)是实现进程同步的”工具“之一,用于控制临界资源的数量,保证各个进程之间的互斥和同步。
(2)可以使用Semaphore类对象实现著名的生产者和消费者问题。
(3)Semaphore对象内部有一个计数器,用于控制访问的资源的数量,或者说是控制访问临界资源的进程的数量,所以创建Semaphore对象时需要传入一个整数。
(4)通过acquire方法获取信号量以访问临界资源,这时semaphore对象的内部计数器就会自减1。当计数器为0时,进程必须等待。
(5)通过release方法释放信号量,这是对象的内部计数器就会自增1,其它想要访问临界资源的进程就可以竞争这个信号量。
multiprocessing.Queue
(1)multiprocessing包中包含了一个Queue类对象作为进程通信的共享队列使用。其它的容器类对象是完全不起效果的,只能使用multiprocessing包中定义的。
(2)当一个队列为空的时候如果再用get取则会阻塞,所以这时候就需要吧blocked设置为false,即非阻塞式,实际上它就会调用get_nowait()方法,此时还需要设置一个超时时间,在这么长的时间内还没有取到队列元素,那就抛出Queue.Empty异常。
(3)当一个队列为满的时候如果再用put放则会阻塞,所以这时候就需要吧blocked设置为false,即非阻塞式,实际上它就会调用put_nowait()方法,此时还需要设置一个超时时间,在这么长的时间内还没有放进去元素,那就抛出Queue.Full异常。
(4)Queue类还包含了很多常用的方法。
multiprocessing.Pipe
(1)Pipe可以是单向(half-duplex),也可以是双向(duplex)。我们通过mutiprocessing.Pipe(duplex=False)创建单向管道 (默认为双向)。一个进程从Pipe一端输入对象,然后被PIPE另一端的进程接收,单向管道只允许管道一端的进程输入,而双向管道则允许从两端输入。
(2)使用send方法向Pipe对象中输入数据。
(3)使用recv方法从Pipe对象中获取数据。
multiprocessing.Pool
(1)Pool类型对象可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。
(2)Pool的用法有阻塞和非阻塞两种方式。
(3)非阻塞也就是添加进程后,不用等待该进程进行完毕就能继续添加下一个进程,阻塞则相反。
(4)非阻塞的Pool对象使用apply_async方法,顾名思义,就是异步的应用Pool对象。
(5)阻塞的Pool对象使用apply方法。
(6)Pool对象还有close方法表示关闭Pool对象,使其不再接受新的任务。
(7)terminate方法用于结束工作进程,不再处理未完成的任务。
(8)同样的也有join方法,用于阻塞主进程,等待子进程执行完毕。join方法要用在close方法和terminate方法之间。
(9)所定义的需要执行的任务可以有返回值,任务的返回值也会作为apply方法和apply_async方法的返回对象返回,然后使用返回对象的get方法获取任务的返回值。
Pool类对象的map方法
(1)Pool对象的map方法适用于使用一个方法处理大量数据。
(2)map方法还有一个函数参数作为需要执行的任务,还有一个参数表示需要处理的数据列表,map方法会自动把数据列表中的每一项作为任务的参数传递给任务。
(3)Pool对象调用map方法时会自动创建进程来执行任务。
具体参考:
静觅 » Python爬虫进阶六之多进程的用法