IO操作不占用cpu
计算占用cpu
python多线程 不适合cpu密集操作类型的任务 适合IO操作密集型任务
简单一个进程实例:
import multiprocessing #进程模块 import time def run(name,proce): time.sleep(1) print("hello",name,proce) if __name__ == '__main__': for i in range(10): p = multiprocessing.Process(target=run,args=('liyang',i,)) p.start() p.join()
进程里面能起线程吗?当然可以:
# -*- coding:utf-8 -*- # Author:Brownyangyang import multiprocessing import time import threading def threadtest(): print(threading.get_ident()) ##获取线程号 def run(name,proce): time.sleep(2) print("hello",name,proce) t = threading.Thread(target=threadtest,) t.start() if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=run,args=('liyang',i,)) p.start() p.join()
关于进程号
import multiprocessing import os def info(title): print(title) print("module name:",__name__) print("parent process:",os.getppid()) ##打印父进程 print("process id:",os.getpid()) ##打印当前进程 print("------------------------") def f(name): info("\033[031;1mfunction f\033[0m") print("hello",name) if __name__ == "__main__": info("\033[032;1mmain process line\033[0m") p = multiprocessing.Process(target=f,args=("liyang",)) p.start() p.join()
结果( 这个310进程是pycharm的进程):
main process line
module name: __main__
parent process: 310
process id: 47385
------------------------
function f
module name: __main__
parent process: 47385
process id: 47386
------------------------
hello liyang
进程间是无法通信,如果非要通信,有以下几种办法:
一、使用进程Queue(这里不同于线程的queue)
# -*- coding:utf-8 -*- # Author:Brownyangyang from multiprocessing import Process,Queue #这里导入的是multiprocessing的Queue模块,不是小写哦,小写queue是线程queue def f(qq): qq.put([42,None,'hello']) if __name__ == '__main__': q = Queue() p = Process(target=f,args=(q,)) #把实例化的队列传到子进程,通过这种方式实现进程间通信。而线程不需这么做。 p.start() print(q.get()) p.join() print("done")
原理是子进程复制了一份数据,然后通过序列化和反序列化再同步给主进程,不同于线程里面的修改数据
二、使用Pipes(管道)数据传递
# Author:Brownyangyang from multiprocessing import Process,Pipe def f(conn): conn.send([42,None,'hello']) ##子进程给父进程发消息 conn.send([40,'liyang','bye']) print(conn.recv()) conn.close() if __name__ == '__main__': parent_conn,clild_conn = Pipe() ##生成管道实例 p = Process(target=f,args=(clild_conn,)) ##这个传哪个都行,也可以传parent_conn p.start() print(parent_conn.recv()) print(parent_conn.recv()) parent_conn.send('hahahhah') ##父进程给子进程发消息 p.join
三、managers 实现数据共享
# -*- coding:utf-8 -*- # Author:Brownyangyang from multiprocessing import Process,Manager import os def f(d,l): d[os.getpid()] = os.getpid() l.append(os.getpid()) 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)
进程锁:虽然进程独立,但是屏幕对于进程是共享的,这个锁只是控制屏幕打印不出现混乱
# -*- coding:utf-8 -*- # Author:Brownyangyang from multiprocessing import Process,Lock def f(lock,i): lock.acquire() print("process id",i) lock.release() if __name__ == '__main__': lock = Lock() for i in range(10): p = Process(target=f,args=(lock,i,)) p.start()
进程池
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。
apply 同步
apply_async 异步
# -*- coding:utf-8 -*- # Author:Brownyangyang from multiprocessing import Process,Pool import time,os #import greenlet def Foo(i): time.sleep(2) print("in process",os.getpid()) return i+10 ##这个参数会作为Bar的参数传递给Bar,这个不是很理解 def Bar(arg): print("-->exec done:",arg,os.getpid()) ##回调 if __name__ == '__main__': pool = Pool(processes=5) ##允许进程池同时放入5个进程 print("主进程",os.getpid()) for i in range(10): pool.apply_async(func=Foo,args=(i,),callback=Bar) #并行,执行完Foo就会执行Bar,这个Bar是主进程执行的,PID和主进程一样 #pool.apply(func=Foo,args=(i,)) 串行 print('end') pool.close() pool.join()##进程池中进程执行完毕后再关闭,如果注释则主程序执行完就退出。
这个callback为什么是主进程写而不是子进程写呢,因为主进程写数据库只要一个长连接,但是如果是子进程需要10个链接,无形拉低了代码效率
结果打印:
主进程 51590
end
in process 51592
in process 51593
in process 51591
in process 51594
in process 51595
-->exec done: 12 51590
-->exec done: 11 51590
-->exec done: 13 51590
-->exec done: 10 51590
-->exec done: 14 51590
in process 51593
in process 51592
in process 51594
in process 51591
in process 51595
-->exec done: 15 51590
-->exec done: 16 51590
-->exec done: 18 51590
-->exec done: 17 51590
-->exec done: 19 51590