python中两个常用来处理进程的模块分别是subprocess和multiprocessing,其中subprocess通常用于执行外部程序,比如一些第三方应用程序,而不是Python程序。如果需要实现调用外部程序的功能,python的psutil模块是更好的选择,它不仅支持subprocess提供的功能,而且还能对当前主机或者启动的外部程序进行监控,比如获取网络、cpu、内存等信息使用情况,在做一些自动化运维工作时支持的更加全面。multiprocessing是python的多进程模块,主要通过启动python进程,调用target回调函数来处理任务,与之对应的是python的多线程模块threading,它们拥有类似的接口,通过定义multiprocessing.Process、threading.Thread,指定target方法,调用start()运行进程或者线程。
在python中由于全局解释锁(GIL)的存在,使用多线程,并不能大大提高程序的运行效率【1】。因此,用python处理并发问题时,尽量使用多进程而非多线程。并发编程中,最简单的模式是,主进程等待任务,当有新任务到来时,启动一个新的进程来处理当前任务。这种每个任务一个进程的处理方式,每处理一个任务都会伴随着一个进程的创建、运行、销毁,如果进程的运行时间越短,创建和销毁的时间所占的比重就越大,显然,我们应该尽量避免创建和销毁进程本身的额外开销,提高进程的运行效率。我们可以用进程池来减少进程的创建和开销,提高进程对象的复用。
实际上,python中已经实现了一个功能强大的进程池(multiprocessing.Pool),这里我们来简单剖析下python自带的进程池是如何实现的。
要创建进程池对象,需要调用Pool函数,函数的声明如下:
Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None)
Returns a process pool object
processes表示工作进程的个数,默认为None,表示worker进程数为cpu_count()
initializer表示工作进程start时调用的初始化函数,initargs表示initializer函数的参数,如果initializer不为None,在每个工作进程start之前会调用initializer(*initargs)
maxtaskperchild表示每个工作进程在退出/被其他新的进程替代前,需要完成的工作任务数,默认为None,表示工作进程存活时间与pool相同,即不会自动退出/被替换。
函数返回一个进程池(Pool)对象
Pool函数返回的进程池对象中有下面一些数据结构:
self._inqueue 接收任务队列(SimpleQueue),用于主进程将任务发送给worker进程
self._outqueue 发送结果队列(SimpleQueue),用于worker进程将结果发送给主进程
self._taskqueue 同步的任务队列,保存线程池分配给主进程的任务
self._cache = {} 任务缓存
self._processes worker进程个数
self._pool = [] woker进程队列
进程池工作时,任务的接收、分配。结果的返回,均由进程池内部的各个线程合作完成,来看看进程池内部由那些线程:
- _work_handler线程,负责保证进程池中的worker进程在有退出的情况下,创建出新的worker进程,并添加到进程队列(pools)中,保持进程池中的worker进程数始终为processes个。_worker_handler线程回调函数为Pool._handler_workers方法,在进程池state==RUN时,循环调用_maintain_pool方法,监控是否有进程退出,并创建新的进程,append到进程池pools中,保持进程池中的worker进程数始终为processes个。
self._worker_handler = threading.Thread(
target=Pool._handle_workers,
args=(self, )
)
Pool._handle_workers方法在_worker_handler线程状态为运行时(status==RUN),循环调用_maintain_pool方法:
def _maintain_pool(self):
if self._join_exited_workers():
self._repopulate_pool()
_join_exited_workers()监控pools队列中的进程是否有结束的,有则等待其结束,并从pools中删除,当有进程结束时,调用_repopulate_pool(),创建新的进程:
w = self.Process(target=worker,
args=(self._inqueue, self._outqueue,
self._initializer, self._initargs,
self._maxtasksperchild)
)
self._pool.append(w)
w是新创建的进程,它是用来处理实际任务的进程,worker是它的回调函数:
def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None):
assert maxtasks is None or (type(maxtasks) == int and maxtasks > 0)
put = outqueue.put
get = inqueue.get
if hasattr(inqueue, '_writer'):
inqueue._writer.close()
outqueue._reader.close() if initializer is not None:
initializer(*initargs) completed = 0
while maxtasks is None or (maxtasks and completed < maxtasks):
try:
task = get()
except (EOFError, IOError):
debug('worker got EOFError or IOError -- exiting')
break if task is None:
debug('worker got sentinel -- exiting')
break job, i, func, args, kwds = task
try:
result = (True, func(*args, **kwds))
except Exception, e:
result = (False, e)
try:
put((job, i, result))
except Exception as e:
wrapped = MaybeEncodingError(e, result[1])
debug("Possible encoding error while sending result: %s" % (
wrapped))
put((job, i, (False, wrapped)))
completed += 1
debug('worker exiting after %d tasks' % completed) 所有worker进程都使用worker回调函数对任务进行统一的处理,从源码中可以看出:
它的功能是从接入任务队列中(inqueue)读取出task任务,然后根据任务的函数、参数进行调用(result = (True, func(*args, **kwds),
再将结果放入结果队列中(outqueue),如果有最大处理上限的限制maxtasks,那么当进程处理到任务数上限时退出。 - _task_handler线程,负责从进程池中的task_queue中,将任务取出,放入接收任务队列(Pipe),
self._task_handler = threading.Thread(
target=Pool._handle_tasks,
args=(self._taskqueue, self._quick_put, self._outqueue, self._pool)
)
Pool._handle_tasks方法不断从task_queue中获取任务,并放入接受任务队列(in_queue),以此触发worker进程进行任务处理。当从task_queue读取到None元素时,
表示进程池将要被终止(terminate),不再处理之后的任务请求,同时向接受任务队列和结果任务队列put None元素,通知其他线程结束。 - _handle_results线程,负责将处理完的任务结果,从outqueue(Pipe)中读取出来,放在任务缓存cache中,
self._result_handler = threading.Thread(
target=Pool._handle_results,
args=(self._outqueue, self._quick_get, self._cache)
) -
_terminate,这里的_terminate并不是一个线程,而是一个Finalize对象
self._terminate = Finalize(
self, self._terminate_pool,
args=(self._taskqueue, self._inqueue, self._outqueue, self._pool,
self._worker_handler, self._task_handler,
self._result_handler, self._cache),
exitpriority=15
)
Finalize类的构造函数与线程构造函数类似,_terminate_pool是它的回调函数,args回调函数的参数。
_terminate_pool函数负责终止进程池的工作:终止上述的三个线程,终止进程池中的worker进程,清除队列中的数据。
_terminate是个对象而非线程,那么它如何像线程调用start()方法一样,来执行回调函数_terminate_pool呢?查看Pool源码,发现进程池的终止函数:
def terminate(self):
debug('terminating pool')
self._state = TERMINATE
self._worker_handler._state = TERMINATE
self._terminate()
函数中最后将_terminate对象当做一个方法来执行,而_terminate本身是一个Finalize对象,我们看一下Finalize类的定义,发现它实现了__call__方法:
def __call__(self, wr=None):
try:
del _finalizer_registry[self._key]
except KeyError:
sub_debug('finalizer no longer registered')
else:
if self._pid != os.getpid():
res = None
else:
res = self._callback(*self._args, **self._kwargs)
self._weakref = self._callback = self._args = \
self._kwargs = self._key = None
return res
而方法中 self._callback(*self._args, **self._kwargs) 这条语句,就执行了_terminate_pool函数,进而将进程池终止。
进程池中的数据结构、各个线程之间的合作关系如下图所示:
aaarticlea/png;base64,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" alt="" />
【1】这里针对的是CPU密集型程序,多线程并不能带来效率上的提升,相反还可能会因为线程的频繁切换,导致效率下降;如果是IO密集型,多线程进程可以利用IO阻塞等待时的空闲时间执行其他线程,提升效率。
未完待续……