进程、线程和协程
进程是计算机中最小的资源分配单位
线程是进程中的一个单位,是计算机中能被CPU调度的最小单位
协程是一个比线程还小的单位
虽然上面说线程是能被调度的最小单位,但是协程不是操作系统可见的,是用户级的,是代码控制切换的
进程
进程就是运行的程序,每一个进程在计算机中都有一唯一的进程id,这个id就是pid(process id)
os.getpid() 获取当前函数在进程中的pid
os.getppid() 获取当前进程的父进程的pid
进程可以 分成子进程,主进程和父进程。主进程是相对的,如果在进程中只看子进程,也可以把这个子进程当成父进程看
Process类是帮助启动\停止进程的
用Process启动子进程
import os import time from multiprocessing import Process def func(a,b,c): time.sleep(1) print(a,b,c,os.getpid(),os.getppid()) if __name__ == '__main__': if __name__ == '__main__': # windows操作系统下开启子进程子进程中的代码是通过import这种方式被导入到子进程中的 print('主 :', os.getpid()) Process(target=func,args=(1,2,3)).start() print('主 :', os.getpid()) Process(target=func,args=(1,2,3)).start()
if __name__=='__main__'
进程中的其他几种方法
is_alive() 判断进程是否还‘活着’
terminate() 终止进程 同步阻塞
开启多个子进程方法
多次执行Process方法就行
join() 同步阻塞
就是 阻塞住 需要等到对应的进程结束之后才能结束阻塞
import random from multiprocessing import Process def send_mail(name): time.sleep(random.uniform(1,3)) print('已经给%s发送邮件完毕'%name) if __name__ == '__main__': lst = ['li','zi','li','zi'] # 阻塞等待一个子进程结束 p = Process(target=send_mail, args=('alex',)) p.start() p.join() # 阻塞,直到p对应的进程结束之后才结束阻塞 print('所有的信息都发送完毕了')
守护进程
守护进程是一个子进程守护主进程
https://www.cnblogs.com/lzlllll/articles/10732127.html
使用面向对象的方式实现多进程
import os from multiprocessing import Process class MyProcess(Process): def run(self): # 希望在子进程中执行的代码就放在run方法中 print(os.getpid()) if __name__ == '__main__': for i in range(10): MyProcess().start()
想要传参数
import os from multiprocessing import Process class MyProcess(Process): def __init__(self,a,b): super().__init__() self.a = a self.b = b def run(self): # 希望在子进程中执行的代码就放在run方法中 print(os.getpid(),self.a,self.b) self.func() if __name__ == '__main__': for i in range(10): MyProcess(1,2).start() # 通知操作系统开进程,执行run方法
注意:一定是重写run方法
Lock类 锁
类似一个锁和钥匙的故事
lock.acquier() 获取钥匙
lock.release() 归还钥匙
锁的应用场景,当多个进程需要操作一个文件\数据的时候
保证对于数据的修改操作,同一时刻只能有一个执行
import json import time from multiprocessing import Process,Lock def search_ticket(name): with open('ticket',encoding='utf-8') as f: dic = json.load(f) print('%s查询余票为%s'%(name,dic['count'])) def buy_ticket(name): with open('ticket',encoding='utf-8') as f: dic = json.load(f) time.sleep(2) if dic['count'] >= 1: print('%s买到票了'%name) dic['count'] -= 1 time.sleep(2) with open('ticket', mode='w',encoding='utf-8') as f: json.dump(dic,f) else: print('余票为0,%s没买到票' % name) def use(name,lock): search_ticket(name) print('%s在等待'%name) # lock.acquire() # print('%s开始执行了'%name) # buy_ticket(name) # lock.release() with lock: print('%s开始执行了'%name) buy_ticket(name) if __name__ == '__main__': lock = Lock() l = ['a','b','c','d'] for name in l: Process(target=use,args=(name,lock)).start()
互斥锁
互斥锁就是在同一个进程中 连续acquice多次产生死锁
死锁现象是acquice之后没有relrase 导致别的进程无法再继续进行
Queue类 队列
put() 传
get() 收# IPC锁 # 队列 # PUT # GET
生产者消费者模型 基于队列把生产数据和消费数据的过程分开了 # #
补充 #
队列 是进程安全的 自带了锁
队列基于什么实现的 文件家族的socket服务
基于文件家族的socket服务实现的ipc机制不止队列一个,管道Pipe #
队列 = 管道 + 锁
管道 是基于文件家族的socket服务实现 # from multiprocessing import Pipe
ipc是通过python的模块是实现的
基于原生的socket,基于进程队列的第三方软件/工具实现的
进程队列——进程安全
生产者和消费者模型
生产者 获取数据
消费者 处理数据
import time import random from multiprocessing import Process,Queue def producer(q): for i in range(10): time.sleep(random.random()) food = '泔水%s'%i print('%s生产了%s'%('taibai',food)) q.put(food) def consumer(q,name): while True: food = q.get() # food = 食物/None if not food : break time.sleep(random.uniform(1,2)) print('%s 吃了 %s'%(name,food)) if __name__ == '__main__': q = Queue() p1 = Process(target=producer,args=(q,)) p1.start() c1 = Process(target=consumer,args=(q,'alex')) c1.start() c2 = Process(target=consumer,args=(q,'wusir')) c2.start() p1.join() q.put(None) q.put(None)
进程池
import os import time from concurrent.futures import ProcessPoolExecutor def make(i): time.sleep(1) print('%s 制作螺丝%s'%(os.getpid(),i)) return i**2 if __name__ == '__main__': p = ProcessPoolExecutor(4) # 创建一个进程池 for i in range(100): p.submit(make,i) # 向进程池中提交任务 p.shutdown() # 阻塞 直到池中的任务都完成为止 print('所有的螺丝都制作完了') p.map(make,range(100)) # submit的简便用法 接收返回值 ret_l = [] for i in range(100): ret = p.submit(make,i) ret_l.append(ret) for r in ret_l: print(r.result()) ret = p.map(make, range(100)) for i in ret: print(i)
线程
也叫轻型进程
不做数据的隔离,在同一进程中的多个线程是可以共享一部分数据的
线程的开启\销毁\切换都比进程要高效很多
GIL锁 全局解释器锁
python当中的多线程,不能访问多个CPU,是python解释器导致的
from threading import Thread
开启线程
Thread(target=函数名,args=元祖)
IO操作 accept()负责从网络上读取数据 open() 调用操作系统的指令开启一个文件
import threading
# threading 和 multiprocessing # 先有的threading模块
# 没有池的功能 # multiprocessing完全模仿threading模块完成的
# 实现了池的功能 # concurrent.futures # 实现了线程池\进程池
开启
import os import time from threading import Thread def func(): time.sleep(1) print('in func',os.getpid()) print('in main',os.getpid()) for i in range(20): # func() Thread(target=func).start()
传参数
import os import time from threading import Thread def func(i): time.sleep(1) print('in func',i,os.getpid()) print('in main',os.getpid()) for i in range(20): # func() Thread(target=func,args=(i,)).start()
在线程部分不需要通过impotr来为新的线程获取代码
所以就不必要if __name__ == '__main__'
线程的其他方法
currentThread()
p=Thread(target=函数名,args=元祖)
currentThread()=p
得到的是当前所在线程的线程对象
p.name() 名字
p.ident() pid
active_count()
返回的是当前有多少个正在工作的线程
import os from threading import Thread,currentThread def func(): t = currentThread() print(t.name,t.ident,os.getpid()) tobj = Thread(target=func) tobj.start() print('tobj :',tobj) t2 = currentThread() print(t2.name,t2.ident,os.getpid())