大家好,今天我们来聊聊Python中的多进程(multiprocessing)编程。你有没有想过,为什么我们可以同时在电脑上做很多事情,比如打开一个浏览器、听音乐、同时还有Word在忙着帮你排版?这就得归功于“多任务”的概念,但你知道吗,背后可有大大的“操作系统魔法”在支撑着呢!

接下来,我们将通过幽默轻松的方式,带你走进多进程的世界。首先,了解操作系统里的神奇魔法,再看看如何用Python来实现它。
一、操作系统的多进程魔法:fork()调用
让我们先从操作系统的“父子关系”谈起——是的,你没听错,进程间居然也有“父子”之分!
在Unix/Linux系统中,有一个特别的系统调用叫做fork(),它的工作原理也相当有趣:一个进程调用fork(),会得到两个返回值,分别是“父进程”和“子进程”。父进程返回的是子进程的ID,而子进程永远返回0。为什么这样设计呢?因为父进程可能要管多个子进程,它得记录下每个子进程的ID,而子进程只要知道自己的父亲是谁就好啦。
pythonimport osprint('Process (%s) start...' % os.getpid())pid = os.fork()if pid == 0:print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))else:print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
运行结果大概是这样的:
scssProcess (876) start...I (876) just created a child process (877).I am child process (877) and my parent is 876.
但是注意!Windows没有这个fork()功能,所以如果你在Windows系统上运行上面的代码,它将无法工作。所以,想在本地实现这个神奇的操作系统魔法,推荐大家用Mac OS X,毕竟它也是基于Unix的嘛!
二、Python的跨平台解决方案:multiprocessing
好消息是,Python不会让你因为Windows没有fork()而痛苦不堪。Python为我们提供了一个跨平台的多进程支持模块——multiprocessing!
这个模块提供了一个Process类,帮助我们更轻松地启动子进程,并且它在不同操作系统上都能正常工作。用起来比fork()方便多了,因为只需要指定一个函数和参数,Python就会帮你搞定启动进程的事。
pythonfrom multiprocessing import Processimport osdef run_proc(name):print('Run child process %s (%s)...' % (name, os.getpid()))if __name__ == '__main__':print('Parent process %s.' % os.getpid())p = Process(target=run_proc, args=('test',))print('Child process will start.')p.start()p.join()print('Child process end.')
运行结果:
arduinoParent process 928.Child process will start.Run child process test (929)...Process end.
这段代码中,p.start()启动子进程,p.join()让父进程等待子进程结束后再继续。你看,多进程操作简直轻松得像打开一个新的网页一样!
三、想要更多子进程?用进程池(Pool)
如果你想要启动多个进程来处理任务怎么办?简单,用进程池(Pool)来批量创建进程。就像你去超市购物,直接拿个购物车,一次性装满所有东西。
pythonfrom multiprocessing import Poolimport os, time, randomdef long_time_task(name):print('Run task %s (%s)...' % (name, os.getpid()))start = time.time()time.sleep(random.random() * 3)end = time.time()print('Task %s runs %0.2f seconds.' % (name, (end - start)))if __name__ == '__main__':print('Parent process %s.' % os.getpid())p = Pool(4)for i in range(5):p.apply_async(long_time_task, args=(i,))print('Waiting for all subprocesses done...')p.close()p.join()print('All subprocesses done.')
在这个例子中,我们创建了一个包含4个进程的进程池,并将5个任务分配给这些进程来执行。注意,最多只能同时执行4个任务,因为进程池的大小是4。你可以修改池的大小,看看结果会有什么不同。
运行时,子进程们会“摇摇晃晃”地开始工作,每个任务执行的时间不一致,最后等待所有任务完成。到了最后,父进程才宣布“所有任务完成!”
四、进程间通信:Queue
进程之间有时候需要“交换信息”,比如,一个进程生成了数据,另一个进程要用这个数据。这时候就需要进程间通信。Python的multiprocessing模块提供了几种方式来让进程互相传递数据,Queue就是最常用的一种。
假设有两个进程,一个负责写数据,另一个负责读数据。我们可以这样写:
pythonfrom multiprocessing import Process, Queueimport os, time, randomdef write(q):print('Process to write: %s' % os.getpid())for value in ['A', 'B', 'C']:print('Put %s to queue...' % value)q.put(value)time.sleep(random.random())def read(q):print('Process to read: %s' % os.getpid())while True:value = q.get(True)print('Get %s from queue.' % value)if __name__ == '__main__':q = Queue()pw = Process(target=write, args=(q,))pr = Process(target=read, args=(q,))pw.start()pr.start()pw.join()pr.terminate()
运行结果:
vbnetProcess to write: 50563Put A to queue...Process to read: 50564Get A from queue.Put B to queue...Get B from queue.Put C to queue...Get C from queue.
通过Queue,进程可以安全地交换数据。这里,父进程创建了一个队列,然后启动两个子进程:一个负责写入数据,另一个负责读取数据。通过q.put()和q.get(),进程间就完成了信息的传递。
*小结
通过multiprocessing模块,Python让我们可以轻松创建多进程程序,而且它还跨平台支持——不论你是Windows、Mac还是Linux,都能轻松搞定!只要掌握了进程池(Pool)、进程通信(Queue)等技术,你就能把你的程序做得像蜘蛛网一样高效、并行运行。
上机题目:让我们动手实践!
题目1:进程池中的并行任务
编写一个Python程序,使用Pool创建10个进程,并让每个进程执行一个任务,任务是计算从1到1000的所有整数之和。
题目2:进程间通信
使用multiprocessing.Queue实现父进程生成一组随机整数,子进程读取并计算这些整数的平均值,然后返回给父进程。
祝你在多进程的世界里畅游!
Python多进程编程全解析

被折叠的 条评论
为什么被折叠?



