目录:
进程与线程配图:
为什么说多线程适合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
