目录:
进程与线程配图:
为什么说多线程适合IO密集型任务,而多进程适合计算密集型任务? IO密集型主要是要在遇到IO时候去尽快的进行切换,而多线程的切换速度快; 计算密集型主要是需要使用CPU的资源,而进程是运行的程序,主要是在使用CPU;
线程=》单指代码的执行过程进程-》资源的申请与销毁的过程
进程:
进程指的就是一个正在运行的程序,或者说是程序的运行过程,即进程是一个抽象的概念.进程之间数据不共享. 进程是起源于操作系统的,是操作系统最核心的概念,操作系统所有其他的概念都是围绕进程展开的
串行:一个任务完完整运行完毕,才执行下一个 并发:多个任务看起来是同时运行的,单核就可以实现并发.本质是不停切换,随机进行 并行:多个任务是真正意义上的同时运行,只有多核才能实现并行 阻塞: 遇到I/O操作,CPU转让给其他进程
1 一个程序只能有一个进程吗? 2 可以 启动一次就产生一个进程 当然可以用代码控制是否允许多进程 3 4 启动进程的方式 5 1.系统初始化,会产生一个根进程 6 2.用户的交互请求,鼠标双击某个程序 7 3.在一个进程中,发起了系统调用启动了另一个进程 ****** 8 4.批处理作业开始,某些专用计算机可能还在使用 9 10 不同操作系统创建进程的方式不同 11 unix < centos mac linux 12 完全拷贝父进程的所有数据,子进程可以访问父进程的数据吗?不可以,但是可以访问拷贝过来数据副本 13 windows 14 创建子进程,导入模块,加载父进程中所有可执行的文件
开启子进程的两种方式:
我们的代码只负责通知操作系统创建进程,创建完就继续其他代码但是操作系统什么时候创建完成,什么时候执行我们无法预知无法控制
1 def task(i): 2 print("%s start" % i) 3 time.sleep(2) 4 print("%s stop" % i) 5 6 if __name__ == '__main__': 7 start_time = time.time() 8 ps = [] 9 for i in range(1,4): 10 p = Process(target=task,args=(i,)) 11 p.start() 12 ps.append(p) 13 # 主进程等子进程结束 14 for p in ps: 15 p.join() 16 17 print("主进程!!!!",time.time()-start_time) 18 # 3 start 进程产生的指令发给了操作系统,但是具体什么时候产生还需要操作系统来决定 19 # 1 start 20 # 2 start 21 # 3 stop 22 # 1 stop 23 # 2 stop 24 # 主进程!!!! 2.134999990463257
方式一:
1 # 方式一(常用): 2 from multiprocessing import Process 3 import time 4 5 def task(x):#子进程的执行代码 6 print('%s is running' %x) 7 print('%s is done' %x) 8 9 if __name__ == '__main__':#兼容window和Linux系统,window系统开启子进程是通过导入的方式拿到父进程数据,Linux是通过直接拷贝拿到 10 # Process(target=task,kwargs={'x':'子进程'}) 11 p=Process(target=task,args=('子进程',)) # 如果args=(),是元组,括号内只有一个参数,一定记住加逗号 12 p.start() # 只是在向操作系统发送一个开启子进程的信号 13 time.sleep(2)#加上睡眠时间,使子进程有足够的时间开启 14 print('主') 15 #子进程 is running 16 #子进程 is done 17 #主 18 如果去掉time.sleep(2),执行结果不同 19 #主 20 #子进程 is running 21 #子进程 is done
方式二:
1 # 方式二:自定义子进程 2 from multiprocessing import Process 3 import time 4 5 class Myprocess(Process): 6 def __init__(self,x): 7 super().__init__() 8 self.name=x 9 10 def run(self):#函数名不能改,start方法自动调用run()方法 11 print('%s is running' %self.name) 12 time.sleep(3) 13 print('%s is done' %self.name) 14 15 if __name__ == '__main__': 16 p=Myprocess('子进程1') 17 p.start() #p.run() 18 print('主') 19 #主 20 #子进程1 is running 21 #子进程1 is done
僵尸和孤儿进程:
僵尸进程: 一个子进程任务执行完就死亡了,但是操作系统不会立即将其清理,为的是让父进程可以访问到这个子进程的运行信息(执行时间,PID等) 子进程死亡,父进程还没结束,没有被操作系统清理的进程称为僵尸进程,越少越好 如果父进程结束了,死亡的子进程会被清理掉.但是如果父进程不结束,且子进程一直循环产生,就会导致僵尸进程越来越多,占用内存和PID 孤儿进程: 孤儿进程是无害!没有爹的称为孤儿.一个父进程已经死亡然而他的子孙进程还在执行着,这时候操作系统会接管这些孤儿进程,最终将其清理
进程内存隔离:join方法
1 from multiprocessing import Process 2 import time 3 4 # 证明进程之间的内存空间彼此隔离 5 x = 100 6 7 def task(): 8 global x 9 x = 0#将子进程内存空间中的x改为了0 10 print('done') 11 12 if __name__ == '__main__': 13 p = Process(target=task) 14 p.start() 15 time.sleep(5) # 让父进程在原地等待,等5s,如果先打印了done,说明先执行了子进程,然后才执行睡眠后的下一行代码 16 print(x)
进程对象的属性和方法:
join:让父进程在原地等待,等到子进程运行完毕后,才执行下一行代码
代码:
1 from multiprocessing import Process 2 import time 3 4 def task(name): 5 print('%s is running ' %name) 6 time.sleep(3) 7 print('%s is done ' % name) 8 9 if __name__ == '__main__': 10 p=Process(target=task,args=('子进程1',)) 11 p.start() 12 p.join() # 让父进程在原地等待,等到子进程运行完毕后,才执行下一行代码 13 print('主')
并发执行代码:
1 from multiprocessing import Process 2 import time 3 4 def task(name,n): 5 print('%s is running ' %name) 6 time.sleep(n) 7 print('%s is done ' % name) 8 9 if __name__ == '__main__': 10 # p1=Process(target=task,args=('子进程1',1)) 11 # p1.start() 12 # p2=Process(target=task,args=('子进程2',2)) 13 # p2.start() 14 # p3=Process(target=task,args=('子进程3',3)) 15 # p3.start() 16 17 p_l=[] 18 start=time.time() 19 for i in range(1,4): 20 p=Process(target=task,args=('子进程%s' %i,i)) 21 p_l.append(p) 22 p.start() 23 24 # print(p_l) 25 for p in p_l: 26 p.join() 27 28 stop=time.time() 29 30 print('主',(stop-start)) 打印结果:
子进程1 is running
子进程3 is running
子进程2 is running
子进程1 is done
子进程2 is done
子进程3 is done
主 3.1440000534057617
pid:
父进程获得子进程的pid-->p1.pid
1 from multiprocessing import Process 2 import time 3 import os 4 5 def task(n): 6 print('%s is running ' %os.getpid()) 7 time.sleep(n) 8 print('%s is done ' % os.getpid()) 9 10 11 if __name__ == '__main__': 12 p1=Process(target=task,args=(10,)) 13 # print(p1.pid) 14 p1.start() 15 print(p1.pid) # 父进程内查看子pid的方式 16 print('主')
进程获得进程自己的pid-->os.getpid(),获得父进程pid-->os.getppid
1 from multiprocessing import Process 2 import time 3 import os 4 5 def task(): 6 print('自己的id:%s 父进程的id:%s ' %(os.getpid(),os.getppid())) 7 time.sleep(200) 8 9 if __name__ == '__main__': 10 p1=Process(target=task) 11 p1.start() 12 print('主',os.getpid(),os.getppid()) 13 # 爹=》主--》儿子
了解方法:
取进程名字:
1 from multiprocessing import Process,current_process 2 import time 3 4 def task(): 5 print('子进程[%s]运行。。。。' %current_process().name)#在当前进程中拿到进程自己的名字 6 time.sleep(200) 7 8 if __name__ == '__main__': 9 p1=Process(target=task,name='子进程1') 10 p1.start() 11 print(p1.name)#在主进程中取子进程的名字 12 print(current_process().name) 13 print('主')
结束进程,判断进程状态:
1 from multiprocessing import Process,current_process 2 import time 3 4 def task(): 5 print('子进程[%s]运行。。。。' %current_process().name) 6 time.sleep(2) 7 8 if __name__ == '__main__': 9 p1=Process(target=task,name='子进程1') 10 p1.start() 11 12 print(p1.is_alive())#True 13 p1.join() 14 print(p1.is_alive())#False 15 16 p1.terminate() 17 time.sleep(1)#休眠让子进程运行 18 print(p1.is_alive())#False 19 print('主')
守护进程:
# 守护进程的代码非常简单 """ p.daemon = True 注意必须在启动进程之前执行 什么时候需要使用守护进程 例如:qq中有个下载视频,应该用子进程去做.但是下载的过程中qq退出,那么下载也没必要继续了 """ from multiprocessing import Process import time def task(): print("妃子 升级为皇后") time.sleep(3) print("皇后 挂了") if __name__ == '__main__': p = Process(target=task) # 将这个子进程设置为当前进程守护进程 p.daemon = True p.start() print("崇祯登基") print("崇祯驾崩了....")
进程互斥锁:
概念及注意事项:
什么时候用锁? 当多个进程,同时读写同一份数据,数据很可能就被搞坏了 第一个进程写了一个中文字符的一个字节,cpu被切到另一个进程,另一个进程也写了一个中文字符的一个字节,最后文件解码失败 问题之所以出现,是因为并发无法控住顺序,目前可以使用join来将所有进程并发改为串行(会降低效率) 与join的区别? 多个进程并发的访问了同一个资源,将导致资源竞争(同时读取不会产生问题,同时修改才会出问题) 第一个方案:加上join,但是这样就导致了不公平,相当于上厕所得按照颜值来 第二个方案:加锁,谁先抢到资源谁先处理 相同点: 都变成了串行 不同点: 1.join顺序固定,锁顺序不固定! 2.join使整个进程的任务全部串行,而锁可以指定哪些代码要串行 锁使是什么? 锁本质上就是一个bool类型的标识符,大家(多个进程)在执行任务之前先判断标识符 互斥锁:两个进程相互排斥 注意:要想锁住资源必须保证,大家拿到锁是同一把 怎么使用? 在需要加锁的地方 lock.acquire() 表示锁定 在代码执行完后 一定要lock.release() 表示释放锁 代码:
lock.acquire() 放需要竞争资源的代码 (同时写入数据) lock.release()
抢票程序:
1 """ 2 抢票! 3 多个用户在同时读写同一个数据 4 要通过互斥锁保证数据安全,避免多人购买了同一张票 5 """ 6 from multiprocessing import Process, Lock 7 import json, time, random 8 9 # 查看余票 10 def show_ticket(name): 11 time.sleep(random.randint(1, 3)) 12 with open(r"ticket.json", "rt", encoding="utf-8") as f: 13 dic = json.load(f) 14 print("%s查看 剩余票数:%s" % (name, dic["count"])) 15 16 # 购买票 17 def buy_ticket(name): 18 # 购买前再次查询 19 with open(r"ticket.json", "rt", encoding="utf-8") as f: 20 # 修改数据 21 dic = json.load(f) 22 if dic["count"] > 0: 23 dic["count"] -= 1 24 # 模拟网络延迟 25 time.sleep(random.randint(1, 3)) 26 # 模拟服务器收到数据 写入文件 27 with open(r"ticket.json", "wt", encoding="utf-8") as f2: 28 json.dump(dic, f2) 29 print("%s 购票成功!" % name) 30 31 def task(lock, name): 32 # 查看余票可以并发执行 不需要锁住 33 show_ticket(name) 34 # 购票的操作需要锁 因为设涉及到同时修改数据 35 lock.acquire() 36 buy_ticket(name) 37 lock.release() 38 39 if __name__ == '__main__': 40 # 买个锁 41 mutex = Lock() 42 for i in range(11): 43 p = Process(target=task, args=(mutex, "客户%s" % i)) 44 p.start() 45 46 # 查询票这个事情,可以多个进程同时执行 47 # 但是买票这个过程,不能同时进行,前一个没买完,后一个就不能买
进程间通讯:
IPC:通过共享内存的方式共享数据(进程间相互隔离)
之所以开启子进程,肯定需要它帮我们完成任务.很多情况下,需要将数据返回给父进程.然而进程内存是物理隔离的 进程间通讯的解决方案: 1.将共享数据放到文件中 速度慢 2.管道PIPE subprocess中的那个管道只能单向通讯,必须存在父子关系 3.共享一块内存区域,让操作系统帮你分配 速度快
第一种:Manager:字典或列表,需要自己处理资源竞争
from multiprocessing import Process,Manager import time def task(dic): print("子进程xxxxx") # li[0] = 1 # print(li[0]) dic["name"] = "xx" if __name__ == '__main__': m = Manager() # li = m.list([100]) dic = m.dict({}) # 开启子进程 p = Process(target=task,args=(dic,)) p.start()#发送开子进程信号 time.sleep(3)#让子进程执行 print(dic)
第二种:队列Queue(区别于queue):先进先出,后进后出,类似扶梯,不用自己处理资源竞争
from multiprocessing import Process, Queue # 基础操作 必须要掌握 # 创建一个队列 q = Queue() # 存入数据 q.put("hello") q.put(["1","2","3"]) q.put(1) # 取出数据 print(q.get()) print(q.get()) print(q.get()) print(q.get()) # 阻塞操作 必须掌握 q = Queue(3) # 存入数据 q.put("hello",block=False) q.put(["1","2","3"],block=False) q.put(1,block=False) # 当容量满的时候 再执行put 默认会阻塞直到执行力了get为止 # 如果修改block=False 直接报错 因为没地方放了 # q.put({},block=False) # 取出数据 print(q.get(block=False)) print(q.get(block=False)) print(q.get(block=False)) # 对于get 当队列中中没有数据时默认是阻塞的 直达执行了put # 如果修改block=False 直接报错 因为没数据可取了 print(q.get(block=False))了解内容:
q = Queue(3) q.put("q", timeout=3) q.put("q2", timeout=3) q.put("q3", timeout=3) # 如果满了 愿意等3秒 如果3秒后还存不进去 就炸 # q.put("q4",timeout=3) print(q.get(timeout=3)) print(q.get(timeout=3)) print(q.get(timeout=3)) # 如果没了 愿意等3秒 如果3秒后还取不到数据 就炸 print(q.get(timeout=3))
生产者消费者模型:
模型,设计模式,三层结构等等表示的都是一种编程套路 生产者指的是能够产生数据的一类任务 消费者指的是处理数据的一类任务 需求: 文件夹里有十个文本文档,要求你找出文件中包含习大大关键字的文件 打开并读取文件数据就是生产者 查找关键字的过程就是消费者 生产者消费者模型为什么出现? 生产者的处理能力与消费者的处理能力不匹配不平衡,导致了一方等待另一方,浪费时间 目前我们通过多进程将生产 和 消费分开处理,然后将生产者生产的数据通过队列交给消费者 在生产者消费者模型中,不仅需要生产者消费者,还需要一个共享数据区域,用来存放多产的数据 1.将生产方和消费方耦合度降低 2.平衡双方的能力,提高整体效率 代码实现 : 搞两个进程,一个负责生产,一个负责消费 数据需要共享所以来个队列
代码:
1 import time, random 2 from multiprocessing import Process, JoinableQueue 3 4 # 当生产者存入队列的数据等于消费者从队列中拿数据的次数,说明结束了 5 6 # 制作热狗 7 def make_hotdog(queue, name): 8 for i in range(3): 9 time.sleep(random.randint(1, 2)) 10 print("%s 制作了一个热狗 %s" % (name, i)) 11 # 生产得到的数据 12 data = "%s生产的热狗%s" % (name, i) 13 # 存到队列中 14 queue.put(data) 15 # 装入一个特别的数据 告诉消费方 没有了 16 17 18 # 吃热狗 19 def eat_hotdog(queue, name): 20 while True: 21 data = queue.get() 22 time.sleep(random.randint(1, 2)) 23 print("%s 吃了%s" % (name, data)) 24 # 该函数就是用来记录一共给消费方多少数据了 就是get次数 25 queue.task_done() 26 27 28 if __name__ == '__main__': 29 # 创建可以等待的队列 30 q = JoinableQueue() 31 # 生产者 32 p1 = Process(target=make_hotdog, args=(q, "邵钻钻的热狗店")) 33 p2 = Process(target=make_hotdog, args=(q, "egon的热狗店")) 34 p3 = Process(target=make_hotdog, args=(q, "老王的热狗店")) 35 # 消费者 36 c1 = Process(target=eat_hotdog, args=(q, "思聪")) 37 c2 = Process(target=eat_hotdog, args=(q, "李哲")) 38 39 p1.start() 40 p2.start() 41 p3.start() 42 43 # 将消费者作为主进程的守护进程 44 c1.daemon = True 45 c2.daemon = True 46 47 c1.start() 48 c2.start() 49 50 # 让主进程等三家店全都做完后.... 51 p1.join() 52 p2.join() 53 p3.join() 54 55 # 如何知道生产方生产完了 并且 消费方也吃完了 56 57 # 方法一:等待做有店都做完热狗在放None 58 # # 添加结束标志 注意这种方法有几个消费者就加几个None 不太合适 不清楚将来有多少消费者 59 # q.put(None) 60 # q.put(None) 61 62 # 方法二:主进程等到队列结束时再继续 那队列什么时候算结束? 生产者已经生产完了 并且消费者把数据全取完了 63 64 # 队列等待没有数据再放入 65 q.join() # 已经明确生产者一共有多少数据 66 67 # 现在 需要知道什么时候做完热狗了 生产者不知道 消费者也不知道 68 # 只有队列知道 69 70 print("主进程over") 71 # 生产方不生产了 然而消费方不知道 所以一直等待 get函数阻塞 72 # 三家店都放了一个空表示没热狗了 但是消费者只有两个 他们只要看见None 就认为没有了 73 # 于是进程也就结束了 造成一些数据没有被处理
=================================================
线程:
进程其实不是一个执行单位,进程是一个资源单位
进程必须等待其内部所有线程都运行完毕才结束
每个进程内自带一个线程,线程是cpu上的执行单位如果把操作系统比喻为一座工厂 在工厂内每造出一个车间===》启动一个进程 每个车间内至少有一条流水线===》每个进程内至少有一个线程线程=》单指代码的执行过程进程-》资源的申请与销毁的过程
进程vs线程 1、 内存共享or隔离 多个进程内存空间彼此隔离 同一进程下的多个线程共享该进程内的数据 2、创建速度 造线程的速度要远远快于造进程
同一进程下的多个线程共享该进程内的数据:第一种方式实现线程:
1 from threading import Thread 2 3 a = 100 4 def task(): 5 global a 6 a = 1 7 print("这是给子线程执行的任务!") 8 9 # 创建一个子线程 10 t = Thread(target=task) 11 # 启动这个子线程 12 t.start() 13 print("主") 14 print(a) 15 16 #这是给子线程执行的任务! 17 #主 18 #1
第二种方式实现线程:
from threading import Thread,current_thread class MyThread(Thread): def run(self): print("run 函数执行!") print(current_thread()) mt = MyThread() mt.start() print(current_thread())
共用一个进程:
1 import time,os 2 3 def task(): 4 time.sleep(2) 5 print("子线程 run.....") 6 print(os.getpid())#8073 7 8 t = Thread(target=task) 9 t.start() 10 # 主线程等到子线程结束 11 t.join() 12 print("over") 13 print(os.getpid())#8073
守护线程:
#守护线程会在本进程内所有非守护的线程都死掉了才跟着死#即 守护线程其实守护的是整个进程的运行周期(进程内所有的非守护线程都运行完毕)
from threading import Thread import time def task(): time.sleep(5) print("子线程...") t = Thread(target=task) t.daemon = True # 守护线程 执行顺序与进程中一样 t.start() print("over")
常用方法:
1 from threading import Thread,current_thread,active_count,enumerate 2 import time 3 4 def task(): 5 print("子线程...") 6 time.sleep(1) 7 # 获取当前线程对象 非常常用 8 print(current_thread()) 9 10 t = Thread(target=task,name="矮根线程!") 11 # t.daemon = True # 守护线程 执行顺序与进程中一样 12 print(t.name) 13 print(t) 14 t.start() 15 # 获取当前活跃线程的数量 16 print(active_count()) 17 # 返回活跃的线程对象枚举 18 print(enumerate()) 19 print("over")
线程互斥锁:
1 from threading import Thread,Lock 2 # 创建一个互斥锁 3 mutex = Lock() 4 5 def task1(): 6 # 锁定 7 mutex.acquire() 8 for i in range(100): 9 print("===================") 10 # 打开 11 mutex.release() 12 def task2(): 13 mutex.acquire() 14 for i in range(100): 15 print("!!!!!!!!!!!!!!!!!!") 16 mutex.release() 17 18 def task3(): 19 mutex.acquire() 20 for i in range(100): 21 print("********************") 22 mutex.release() 23 24 t1 = Thread(target=task1) 25 t2 = Thread(target=task2) 26 t3 = Thread(target=task3) 27 28 t1.start() 29 t2.start() 30 t3.start()
线程死锁:
1 from threading import Thread, Lock, current_thread, RLock 2 import time 3 4 # 叉子 5 locka = RLock() 6 # 盘子 7 lockb = RLock() 8 9 10 def task1(): 11 print(current_thread()) 12 locka.acquire() 13 print("抢到叉子 需要盘子") 14 time.sleep(0.1) 15 lockb.acquire() 16 print("吃饭") 17 18 lockb.release() 19 locka.release() 20 21 22 def task2(): 23 print(current_thread()) 24 lockb.acquire() 25 print("抢到盘子 需要叉子") 26 time.sleep(0.1) 27 locka.acquire() 28 29 print("吃饭") 30 locka.release() 31 lockb.release() 32 33 34 t1 = Thread(target=task1) 35 t1.start() 36 t2 = Thread(target=task2) 37 t2.start() 38 39 # 死锁发生的条件 有多个线程 多个锁 如果只有一个锁 无论是LOCK RLOK 卡不死(前提是逻辑上没有错误) 40 # RLock 就算你的代码逻辑不对 同一个线程多次对一个锁执行acquire 也不会卡死
线程递归锁,重用锁:
#普通互斥锁不能重用,重用会阻塞# 从线程导入RLock,递归锁 重用锁,可以多次执行acquire lock = RLock() lock.acquire() print("aaaaaaaaaaa") lock.acquire() print("bbbbbbbbbbb")
线程中使用重用锁:
import time lock = RLock() # 对于同一个线程而言,可以多次acquire.其他线程会被阻塞,不会锁死 def task(): lock.acquire() lock.acquire() for i in range(5): time.sleep(0.5) print(current_thread()) lock.release() lock.release() Thread(target=task).start() Thread(target=task).start()
event:
事件是什么? 某件事情发生的信号 用来干什么? 在线程间通讯,然而线程本来就能通讯 作用只有一个就是简化代码 线程间通讯的例子: 服务器启动需要五秒 客户端启动后去连接服务器 去连接服务器必须保证服务器已经开启成功了 是否启动完成就是要通讯的内容. 注意:Event线程通讯,仅仅用于简单的条件判断,说白了代替bool类型和if判断 set() 将状态修改为True wati() 等待状态为True才继续执行
代码实现:
原始实现:
1 import time 2 from threading import Thread 3 boot = False 4 def server_task(): 5 global boot 6 print("正在启动....") 7 time.sleep(5) 8 print("启动....成功") 9 boot = True 10 11 def client_task(): 12 while True: 13 print("连接服务器....") 14 time.sleep(1) 15 if boot: 16 print("连接成功") 17 break 18 else: 19 print("error 连接失败 服务器未启动!!") 20 21 t1 = Thread(target=server_task) 22 t1.start() 23 24 t2 = Thread(target=client_task) 25 t2.start() 26 27 t1.join() 28 t2.join()
event实现:
1 # 使用事件实现 2 3 import time 4 from threading import Thread,Event 5 event =Event() 6 7 def server_task(): 8 print("正在启动....") 9 time.sleep(5) 10 print("启动....成功") 11 event.set() 12 13 def client_task(): 14 event.wait() #一个阻塞的函数 会阻塞直到对event执行set函数为止 15 print("连接成功!") 16 17 t1 = Thread(target=server_task) 18 t1.start() 19 t2 = Thread(target=client_task) 20 t2.start()
信号量:
# 信号量是控制同一时刻并发执行的任务数
1 from threading import Thread,Semaphore,current_thread,active_count 2 3 import time 4 # 用于控制同时执行被锁定代码的线程数量,也就是线程的并发数量 5 # 也是一种锁 6 sm = Semaphore(5) 7 8 def task(): 9 sm.acquire() 10 for i in range(10): 11 print(current_thread()) 12 time.sleep(0.5) 13 sm.release() 14 15 def task2(): 16 for i in range(10): 17 print(current_thread()) 18 time.sleep(0.5) 19 20 for i in range(5): 21 Thread(target=task).start() 22 Thread(target=task2).start() 23 print(active_count())#11,包含主线程
池:
什么是? 池:池用来限制进程/线程个数的一种机制 为何用? 当并发的任务数远大于计算机的承受能力,应该用池的概念 将并发的进程数/线程数控制在计算机能承受的数目
进程池:
进程池就是一个装进程的容器 为什么出现? 当进程很多的时候方便管理进程 什么时候用? 当并发量特别大的时候.例如双十一 很多时候用户停留在进程,没有别的操作,进程是空闲的,就让他进入进程池,让有任务处理时才从进程池取出来使用 进程池使用: ProcessPoolExecutor类 创建时指定最大进程数,进程池会自动创建进程 调用submit函数将任务提交到进程池中 创建进程是在调用submit后发生的,会直接在进程池内创建对应个数的进程
有什么特点: 1.管理进程的创建 2.管理进程的销毁 3.负责任务的分配 4.控制最大并发数量注意:用池来处理TCP是不正确的,因为进程中代码执行完毕才算空闲
基于进程池实现并发套接字通信:
服务端:
线程池默认为核数4
客户端:客户端可以同时连接服务端的最大连接数 = 线程池参数
同时只能有四个客户端能交互
线程池:
1 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 2 from threading import current_thread 3 4 import os,time,random 5 6 def task(): 7 time.sleep(random.randint(1,2)) 8 print(current_thread()) 9 10 def run(): 11 # 默认为cpu核心数 12 pool = ThreadPoolExecutor(3) 13 for i in range(30): 14 pool.submit(task) 15 16 if __name__ == '__main__': 17 run()
来源:https://www.cnblogs.com/xuechengeng/p/9925644.html