Python基础知识点:进程相关知识点梳理,推荐收藏
发布时间:2022-09-24 12:51:26 所属栏目:Unix 来源:
导读: Python实现多进程的方式主要有两种:一种方法是使用os模块中的fork方法; 另一种是使用multiprocessing模块。这两种方法的区别在于前者仅适用于Unix/Linux操作操作。对win是不支持的,而后者则是跨平台的实现方式
|
Python实现多进程的方式主要有两种:一种方法是使用os模块中的fork方法; 另一种是使用multiprocessing模块。这两种方法的区别在于前者仅适用于Unix/Linux操作操作。对win是不支持的,而后者则是跨平台的实现方式。 使用os模块中的fork方式实现多进程。 Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次unix进程通信,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。 子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。 Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程: import os print( '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)) 得到: Process (2450) start... I (2450) just created a child process (2451). I am child process (2451) and my parent is 2450. 使用Multiprocessing查模块创建多进程。 multiprocessing模块提供了一个Process类来描述一个进程对象,创建子进程时,只需要传入一个执行函数和函数的参数即可完成一个Process实例的创建,用start()方法启动进程,用join()方法实现进程间的同步。join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。 # -*- coding:utf-8 -*- from multiprocessing import Process import os # 子进程要执行的代码 def 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('Process will start.') p.start() p.join() print('Process end.') 得到: Parent process 2533. Process will start. Run child process test (2534)... Process end. multiprocessing模块提供了一个pool类来代表进程池对象 Pool可以提供指定数量的进程供用户调用,默认大小是cpu的核数,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求,但如果池的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束才会创建新的进程来处理它。 # -*- coding:utf-8 -*- from multiprocessing import Pool import os, time, random 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() 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.') 得到: Parent process 2541. Waiting for all subprocesses done... Run task 0 (2543)... Run task 1 (2544)... Run task 2 (2545)... Run task 3 (2546)... Task 0 runs 0.02 seconds. Run task 4 (2543)... Task 2 runs 0.60 seconds. Task 4 runs 1.18 seconds. Task 3 runs 1.26 seconds. Task 1 runs 1.66 seconds. All subprocesses done. 对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。 进程间的通信 Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。两者的区别在于Pipe常用于两个进程间的通讯而Queue用于多个进程间实现通讯。 Queue通讯 Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传输,有两个方法:put和get进行Queue操作。 # -*- coding:utf-8 -*- from multiprocessing import Process, Queue import os, time, random # 写数据进程执行的代码: def write(q): for value in ['A', 'B', 'C']: print('Put %s to queue...' % value) q.put(value) time.sleep(random.random()) # 读数据进程执行的代码: def read(q): 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() 得到: Put A to queue... Get A from queue. Put B to queue... Get B from queue. Put C to queue... Get C from queue. Pipes通讯 Pipe常用来在两个进程间进行通信,两个进程分别位于管道的两端。 Pipe方法返回(conn1,conn2)代表一个管道的两个端,Pipe方法有duplex参数,如果duplex参数为True(默认值),那么这个管道是全双工模式,也就是说conn1和conn2均可收发,若duplex为False,conn1只负责接收消息,conn2只负责发送消息。send和recv方法分别是发送和接收消息的方法。例如,在全双工模式下,可以调用conn1.send发送消息,conn1.recv接收消息。如果没有消息可接收,recv方法会一直阻塞。如果管道已经被关闭,那么recv方法会抛出EOFError. import multiprocessing import random import time, os def proc_send(pipe, urls): for url in urls: print('process(%s) send:%s' % (os.getpid(), url)) pipe.send(url) time.sleep(random.random()) def proc_recv(pipe): while True: print ('Process(%s) rev:%s' % (os.getpid(), pipe.recv())) time.sleep(random.random()) if __name__ == "__main__": pipe = multiprocessing.Pipe() p1 = multiprocessing.Process(target=proc_send,args=(pipe[0],['url_'+str(i) for i in range(10)])) p2 = multiprocessing.Process(target=proc_recv,args=(pipe[1],)) p1.start() p2.start() p1.join() p2.join() 得到: process(1134) send:url_0 Process(1135) rev:url_0 process(1134) send:url_1 Process(1135) rev:url_1 process(1134) send:url_2 Process(1135) rev:url_2 process(1134) send:url_3 Process(1135) rev:url_3 process(1134) send:url_4 Process(1135) rev:url_4 process(1134) send:url_5 Process(1135) rev:url_5 process(1134) send:url_6 Process(1135) rev:url_6 process(1134) send:url_7 Process(1135) rev:url_7 process(1134) send:url_8 Process(1135) rev:url_8 process(1134) send:url_9 Process(1135) rev:url_9 (编辑:百客网 - 百科网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐
