NO.4 Python多进程
零蚀
-
多任务
- 并发:cpu进行分配时间片,看起来像并行。
- 并行:多个cpi同时工作,多个程序同时工作。
-
进程编写
import multiprocessing as mp import os def function(): print("加油") print(mp_process.name) if __name__ == '__main__': mp_process = mp.Process(target=function) mp_process.start() print(mp_process.pid) # 进程id print(mp.current_process()) # 当前进程对象 print("cpu_count:", mp.cpu_count()) # cpu数量 print("父进程id:", os.getppid())
- 参数的传递
def function(a, b, c): print("加油", a, b, c) print(mp_process.name) if __name__ == '__main__': # mp_process = mp.Process(target=function, args=(1, 2, 3)) mp_process = mp.Process(target=function, kwargs={"a": 1, "b": 2, "c": 3}) mp_process.start()
- 进程的共享
进程是不能数据通信的,也就是说不可以做到数据共享,案例如下:
num = 0 def a(): global num for i in range(100000): num = num + 1 print("a:", num) def b(): global num for i in range(100000): num = num + 1 print("b:", num) if __name__ == '__main__': # mp_process = mp.Process(target=function, args=(1, 2, 3)) mp_process = mp.Process(target=a) mp_process.start() mp_process1 = mp.Process(target=b) mp_process1.start() time.sleep(3) print("main:", num)
输出的结果为:
a: 100000 b: 100000 main: 0
- 守护线程
# 终结当前进程 mp_process.terminate() # or # 设置守护进程() mp_process.daemon=True
mp_process.daemon需要在start之前,且执行到时也是干掉子进程,并且干掉了子进程里面的所有缓存资源对象。
- 消息队列
进程数据示意图:
添加消息队列
- 队列的特性
queue = multiprocessing.Queue(3) queue.put(1) queue.put("abcd") queue.put(["aaa","bbb"]) # 如果队列已满,阻塞程序,直到队列熟取出 # queue.put(1234) # 拿到队头,取出队列 head = queue.get() print(head) head1 = queue.get() print(head1) head2 = queue.get() print(head2)
如果put 或get过多会导致阻塞,致使其他代码无法继续运行。为了防止阻塞导致崩溃。
# 添加不了,报异常 queue.put_nowait("adf") # 获取不到,报异常 queue.get_nowait()
设置超时时间,这样也可以起到报错的效果
head4 = queue.get(timeout=3) print(head4)
其他API
queue.full() # 判满 queue.empty() # 判空(3.7+ ;添加数据需要时间,在添加的过程中还是为空) queue.qsize() # 判size
- 进程间通信
def put_data(queue): for i in range(10): print("放数据:", i) queue.put(i) time.sleep(1) def get_data(queue): while True: print("取数据:", queue.get(timeout=3)) time.sleep(1) if __name__ == '__main__': queue = mp.Queue() mp1 = mp.Process(target=put_data, args=(queue,)) mp2 = mp.Process(target=get_data, args=(queue,)) mp1.start() mp2.start()
- 进程池
def funcA(str): time.sleep(1) print("任务A", str) iif __name__ == '__main__': pool = mp.Pool(3) for i in range(10): # 指派任务,按照队列任务完成 pool.apply(funcA, ("fjasfj;" + str(i),)) pool.close()
阻塞当前代码,至当前进程池所有进程执行完毕。
pool.join()
在进程运行之前或之后运行相应代码。
result=pool.apply_async(funcA, ("f",)) # .... result.wait()
- 进程池的任务队列
进程池的队列需要特殊指定的消息队列:
def write(queue): for i in range(10): print("写入数据",i) queue.put(i) time.sleep(1) def read(queue): while True: print("读取数据",) value = queue.get() print("读取数据",value) if __name__ == '__main__': queue = mp.Manager().Queue(3) pool = mp.Pool(2) pool.apply_async(write, (queue,)) pool.apply_async(read, (queue,)) pool.close() pool.join()
这里的线程池任务指定,需要指定为异步操作,不然会卡死在某一个apply上,由于队列大小不够。
其他API
import os os.mkdir("path") os.makedirs("paths") # 遍历dir os.listdir("path")
- 进程锁
比如多个进程写同一个文件
import multiprocessing # 对文件file进行写入操作 # "file.txt" def write_one(file, lock): with lock: with open(file, "+a") as file1: for i in range(10): file1.write("aaa---"+str(i)+ "---") def write_two(file, lock): with lock: with open(file, "+a") as file2: for i in range(10): file2.write("bbb---"+str(i)+"---") if __name__ == '__main__': lock = multiprocessing.Lock() path = "file.txt" p1 = multiprocessing.Process(target=write_one, args=(path, lock)) p2 = multiprocessing.Process(target=write_two, args=(path, lock)) p1.start() p2.start()
- fork()
fork主要存在于unix/linux下,也就是mac/linux系统系统,他调用就会产生一个子进程。windows没有fork无法运行,fork会返回两次,一个是当前进程,一个是子进程:
import os import multiprocessing fork_pid = os.fork() print("pid:", fork_pid) if fork_pid != 0: print('我是主进程', multiprocessing.current_process().name) else: print('我是子进程', multiprocessing.current_process().name)
输出:
pid: 36396 我是主进程 34814 pid: 0 我是子进程 36395
- PIPE管道
主要目的还是做进程间通信,PIPE分单双工和全双工,单双工是指通信双方只能有一个发起者和一个接收者,当存在发起者存在的时候,另一方只能由对方完毕之后,才能进行通信。
半双工
def sender_process(pipe): for i in range(10): print("发送方——>pip2", i) pipe.send(i) time.sleep(1) def receive_process(pipe): while True: print("接收方——>pip2", pipe.recv()) time.sleep(1) if __name__ == '__main__': # false 单双工, True 全双工 pipe = mp.Pipe(duplex=False) p1 = mp.Process(target=receive_process, args=(pipe[0],)) p2 = mp.Process(target=sender_process, args=(pipe[1],)) p1.start() p2.start()
主要的方法是pipe.send(i)和pipe.recv()
🔗 前言
🔗 Python 高级列表
🔗 NO.1 Python网络通信
🔗 NO.2 Python Web 服务器
🔗 NO.3 Python多线程&锁
🔗 NO.5 Python协程&生成器
🔗 NO.6 Python正则&爬虫初
🔗 NO.7 Python操作MySQL
🔗 NO.8 Python Spider
🔗 NO.9 Python 装饰器&other