线程与进程 之进程
多进程multirocessing
有效的绕过了全局解释器锁(GIL)!! 可以使用真正的多核.
写法跟多线程一毛一样。
from multiprocessing import Process import time def f(name): time.sleep(2) print('hello', name) if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join()
创建一个新的进程的开销远比线程 大的多的多的多。。。。
from multiprocessing import Process import os def info(title): print(title) print('module name:', __name__) print('parent process:', os.getppid()) print('process id:', os.getpid()) print("\n\n") def f(name): info('\033[31;1mfunction f\033[0m') print('hello', name) if __name__ == '__main__': info('\033[32;1mmain process line\033[0m') p = Process(target=f, args=('bob',)) p.start() p.join()
os.getppid() 获取父进程的PID号
os.getpid() 获取当前进程PID号
进程间通信
实现了双方数据的传递,并没有实现数据的共享,并同时修改一份数据.
Queue(队列)
不同的进程间内存是不共享的,要想实现两个进程间的数据交换.
可以用队列的方法
A进程给队列中放,B进程去队列中取
from multiprocessing import Process, Queue def f(q): q.put([42, None, 'hello']) if __name__ == '__main__': q = Queue() p = Process(target=f, args=(q,)) p.start() print(q.get()) # prints "[42, None, 'hello']" p.join()
这里要注意的是 :
1.先声明一个q 为队列。
2.在声明一个p为子进程
3.因为是多进程的通信通过的是队列,所以需要把 队列中的数据,传递给p这个进程,p这个进程才可以访问
4.进程的内存是独立的, 线程的内存是共享的。
Pipe(管道)
from multiprocessing import Process,Pipe #管道 def f(conn): conn.send([42,None,'父亲']) conn.send([43,None,'word']) print('from parent',conn.recv()) conn.close() if __name__ == '__main__': parent_conn,child_conn = Pipe() #管道 一个头一个尾 就好比 一个父亲 一个儿子 p = Process(target=f,args=(child_conn,)) #定义是用来接受子请求 p2 = Process(target=f, args=(child_conn,)) p.start() p2.start() print(parent_conn.recv()) #打印 父去接受子的请求 parent_conn.send('hellow 儿子') parent_conn.send('hellow 儿2子') p.join() p2.join()
剖析:
1.Pipe() 这里产生了2个进程 一个为 父进程parent_conn,一个为子进程child_conn
2.send为发,recv为接受
3.创建2个进程,并把子进程传递给这个函数,这个函数就相当于打印出子进程.
3.父进程进程可以send多次。。子进程只能recv 接受一次。。
Managers
可以实现进程直接数据的交互修改
实际上:进程之间的数据是没有办法直接修改的,不会像线程那样真正修改同一份数据。
那进程之间修改同一份数据,是主进程把这份数据先copy 或者socket,或者内存映射的方法,把一块内存给共享出来。 这些方法 给另外一个A进程,A进程改完后,在返回给主进程.然后主进程在把数据copy给C进程,D进程.
所以开销是非常大, 这种的进程之间数据共享修改,涉及到进程间数据的来回copy。非常耗资源....
from multiprocessing import Process, Manager def f(d, l): d[1] = '1' d['2'] = 2 d[0.25] = None l.append(1) print(l) if __name__ == '__main__': with Manager() as manager: d = manager.dict() l = manager.list(range(5)) p_list = [] for i in range(10): p = Process(target=f, args=(d, l)) p.start() p_list.append(p) for res in p_list: res.join() print(d) print(l)
阿。。。。用是这么用。但是还是不会。。。
进程同步
from multiprocessing import Process, Lock def f(l, i): l.acquire() try: print('hello world', i) finally: l.release() if __name__ == '__main__': lock = Lock() for num in range(100): Process(target=f, args=(lock, num)).start()
这个东东。就是用来保证屏幕输出正常。。。。应该是2个进程 公用一个屏幕
#这里用到了进程锁。。。。 保证子进程 输出一致
进程池
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止.
进程中 有两个方法:
#导入multiprocessing 中的Pool方法
#apply 阻塞的
#apply_async 非阻塞的
#close 关闭pool,使其不再接受其他新的任务
#join() 主进程阻塞,等待子进程的退出,join方法要在close后使用
from multiprocessing import Process, Pool,Lock import time def f(i): print('hello word %s' %i) time.sleep(1) return i def callback(data): #回执,相当于 子进程执行完毕后。告诉主进程. 这里callback还可以干很多事,因为这里设置的是把结果都返回给这里了。。所以可以把结果写入日志中 print('exec done---->',data) if __name__ == '__main__': lock =Lock() pool = Pool(processes=5) #设置线程池,有5个进程 for num in range(100): pool.apply_async(func=f,args=(num,),callback=callback) pool.close() #一定要close() 。告诉主进程说,进程池已经添加完毕,可以关闭了 pool.join() #进程池中进程执行完毕后在关闭。如果取消,那么程序直接就关闭了

浙公网安备 33010602011771号