python笔记—进程笔记
多进程模式:在操作系统上一个任务就是一个进程,例如打开一个笔记本,打开一个浏览器,打开一个word文档或者打开播放器,单核cpu上的任务都是轮流进行的,只是cpu处理太快我们没感觉,多核CPU可以实现多个 任务同时进行,进程的调度都是于系统进行,进程本身不能控制。
多线程模式:线程是进程中的一项子任务,列如在word文档中会有拼写检查,打印,打字需要同时运行,在一个进程运行的多个子任务就叫线程
多进程多线程模式:启动多个进程和多线程可以同时执行的任务更多,模型也更复杂
多进程
Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。
1 import os 2 3 print('Process (%s) start...' % os.getpid()) 4 # Only works on Unix/Linux/Mac: 5 pid = os.fork() 6 if pid == 0: 7 print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) 8 else: 9 print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
运行结果如下:
Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.
由于Windows没有fork调用,上面的代码在Windows上无法运行。
multiprocessing
由于Windows没有fork调用,需要用另一个模块multiprocessing
multiprocessing模块中提供了Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:
# 子进程要执行的代码 def run_proc(name): # 获取子进程ID print('Run child process %s (%s)...' % (name,os.getpid())) if __name__ == '__main__': # 获取父进程ID print('Parent process %s.'% os.getpid()) # 创建一个Process 实例,调用函数和函数的参数。生成一个字进程 p = Process(target=run_proc,args=('test',)) print('Chid process will start') # 启动子进程 p.start() # 等待子进程结束后再往下运行,通常用于进程间的同步 p.join() print('Child process end.')
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
Pool
如果要启动大量的子进程,可以用进程池的方式批量创建子进程:
def 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) # 每个线程分工调用五次函数,由于默认是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.')
进程间通信
Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。
我们以Queue为例,在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读数据:
def 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__': # 父进程创建Queue,并传给各个子进程 q = Queue() pw = Process(target=write,args=(q,)) pr = Process(target=read,args=(q,)) # 启动子进程pw,写入: pw.start() # 启动子进程pr,读取: pr.start() # 等待pw进程结束 pw.join() # pr进程是死循环,无法等待其结束,只能强行终止 pr.terminate()
小结
在Unix/Linux下,可以使用fork()调用实现多进程。
要实现跨平台的多进程,可以使用multiprocessing模块。
进程间通信是通过Queue、Pipes等实现的。
摘自廖雪峰老师网站:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431927781401bb47ccf187b24c3b955157bb12c5882d000

浙公网安备 33010602011771号