线程池和进程池以及线程queue
线程queue
既然有进程的队列,那么也会有线程的queue
线程的queue有三种方式
并且导入模块的方式和进程不一样
先进先出
import queue
q = queue.Queue()#
q.put('123')
q.put('qweqwe')
print(q.get())
print(q.get())
# print(q.get())
q.task_done()
q.task_done()
q.join()
123
qweqwe
和之前的joinablequeue一样,这个需要用task_done来减掉计数器的值。不然join那里就会一直阻塞住。这是先进先出。
先进后出
q = queue.LifoQueue() #堆栈 先进后出
q.put('粉红色的背心儿')
q.put('粉红色的裤子')
q.put('欧文的各种设备')
print(q.get())
print(q.get())
print(q.get())
q.task_done()
q.task_done()
q.task_done()
q.join()
欧文的各种设备
粉红色的裤子
粉红色的背心儿
按照优先级
q = queue.PriorityQueue() # 可以根据优先级取数据
# 通常这个元组的第一个值是int类型
q.put((50,'ccc'))
q.put((80,'bbb'))
q.put((1,'aaa'))
print(q.get())
print(q.get())
print(q.get())
q.task_done()
q.task_done()
q.task_done()
q.join()
(1, 'aaa')
(50, 'ccc')
(80, 'bbb')
线程定时器
就是定时多久开启一个线程,并且不会阻塞住。
from threading import Thread,Timer
import time
def task():
print('线程执行了')
time.sleep(2)
print('线程结束了')
t = Timer(4,task) # 过了4s后开启了一个线程
t.start()
print('qweqweqwe')
qweqweqwe
线程执行了
线程结束了
这里打印qweqweqwe没有被阻塞,而是直接就打印了,并没有等待4秒,因为不会阻塞,
这也是为什么有这个方法,而不用time.sleep的原因,因为sleep会阻塞住。
进程池和线程池
为什么要有进程池?进程池的概念。
在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。那么我们要怎么做呢?
在这里,要给大家介绍一个进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果
线程池也一样。
同步和异步的区别
同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码
异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time
def task(i):
print(f'{currentThread().name} 在执行任务 {i}')
# print(f'进程 {current_process().name} 在执行任务 {i}')
time.sleep(1)
return i**2
if __name__ == '__main__':
pool = ThreadPoolExecutor(4) # 池子里只有4个线程
# pool = ProcessPoolExecutor(4) # 池子里只有4个线程
fu_list = []
for i in range(20):
# pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
#fu_list.append(future)
#pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
#for fu in fu_list:
#print(fu.result())
ThreadPoolExecutor-0_0 在执行任务 0
0
ThreadPoolExecutor-0_0 在执行任务 1
1
ThreadPoolExecutor-0_1 在执行任务 2
4
ThreadPoolExecutor-0_0 在执行任务 3
9
ThreadPoolExecutor-0_2 在执行任务 4
16
ThreadPoolExecutor-0_1 在执行任务 5
25
ThreadPoolExecutor-0_3 在执行任务 6
36
ThreadPoolExecutor-0_0 在执行任务 7
49
ThreadPoolExecutor-0_2 在执行任务 8
64
ThreadPoolExecutor-0_1 在执行任务 9
81
ThreadPoolExecutor-0_3 在执行任务 10
100
ThreadPoolExecutor-0_0 在执行任务 11
121
ThreadPoolExecutor-0_2 在执行任务 12
144
ThreadPoolExecutor-0_1 在执行任务 13
169
ThreadPoolExecutor-0_3 在执行任务 14
196
ThreadPoolExecutor-0_0 在执行任务 15
225
ThreadPoolExecutor-0_2 在执行任务 16
256
ThreadPoolExecutor-0_1 在执行任务 17
289
ThreadPoolExecutor-0_3 在执行任务 18
324
ThreadPoolExecutor-0_0 在执行任务 19
361
这就是同步了,因为你打印一定要等到他拿到这个result才能继续。
因此,改良了一下
'''
进程池线程池:
池的功能限制进程数或线程数.
什么时候限制?
当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
\我就应该考虑去限制我进程数或线程数,从保证服务器不崩.
'''
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time
def task(i):
print(f'{currentThread().name} 在执行任务 {i}')
# print(f'进程 {current_process().name} 在执行任务 {i}')
time.sleep(1)
return i**2
if __name__ == '__main__':
pool = ThreadPoolExecutor(4) # 池子里只有4个线程
# pool = ProcessPoolExecutor(4) # 池子里只有4个线程
fu_list = []
for i in range(20):
# pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
# print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
fu_list.append(future)
pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
for fu in fu_list:
print(fu.result())
ThreadPoolExecutor-0_0 在执行任务 0
ThreadPoolExecutor-0_1 在执行任务 1
ThreadPoolExecutor-0_2 在执行任务 2
ThreadPoolExecutor-0_3 在执行任务 3
ThreadPoolExecutor-0_2 在执行任务 4
ThreadPoolExecutor-0_0 在执行任务 5
ThreadPoolExecutor-0_1 在执行任务 6
ThreadPoolExecutor-0_3 在执行任务 7
ThreadPoolExecutor-0_0 在执行任务 8
ThreadPoolExecutor-0_2 在执行任务 9
ThreadPoolExecutor-0_1 在执行任务 10
ThreadPoolExecutor-0_3 在执行任务 11
ThreadPoolExecutor-0_1 在执行任务 12
ThreadPoolExecutor-0_0 在执行任务 13
ThreadPoolExecutor-0_2 在执行任务 14
ThreadPoolExecutor-0_3 在执行任务 15
ThreadPoolExecutor-0_1 在执行任务 16
ThreadPoolExecutor-0_2 在执行任务 17
ThreadPoolExecutor-0_0 在执行任务 18
ThreadPoolExecutor-0_3 在执行任务 19
0
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
289
324
361
把所有的future都放进列表,然后列表一起拿结果。但是这样消耗的时间还是太多了。
于是就有了一个叫做回调函数的东西。
'''
进程池线程池:
池的功能限制进程数或线程数.
什么时候限制?
当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
\我就应该考虑去限制我进程数或线程数,从保证服务器不崩.
理解为提交任务的两种方式
同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码,
异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.
'''
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time
def task(i):
print(f'{currentThread().name} 在执行任务 {i}')
# print(f'进程 {current_process().name} 在执行任务 {i}')
time.sleep(1)
return i**2
def parse(future):
# 处理拿到的结果
print(future.result())
if __name__ == '__main__':
pool = ThreadPoolExecutor(4) # 池子里只有4个线程
# pool = ProcessPoolExecutor(4) # 池子里只有4个线程
fu_list = []
for i in range(20):#4
# pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
future.add_done_callback(parse)
# 为当前任务绑定了一个函数,在当前任务执行结束的时候会触发这个函数,
# 会把future对象作为参数传给函数
# 这个称之为回调函数,处理完了回来就调用这个函数.
# print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
# pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
# for fu in fu_list:
# print(fu.result())
ThreadPoolExecutor-0_0 在执行任务 0
ThreadPoolExecutor-0_1 在执行任务 1
ThreadPoolExecutor-0_2 在执行任务 2
ThreadPoolExecutor-0_3 在执行任务 3
0
ThreadPoolExecutor-0_0 在执行任务 4
1
ThreadPoolExecutor-0_1 在执行任务 5
4
ThreadPoolExecutor-0_2 在执行任务 6
9
ThreadPoolExecutor-0_3 在执行任务 7
16
ThreadPoolExecutor-0_0 在执行任务 8
25
ThreadPoolExecutor-0_1 在执行任务 9
36
ThreadPoolExecutor-0_2 在执行任务 10
49
ThreadPoolExecutor-0_3 在执行任务 11
64
ThreadPoolExecutor-0_0 在执行任务 12
100
81
ThreadPoolExecutor-0_1 在执行任务 13
ThreadPoolExecutor-0_2 在执行任务 14
121
ThreadPoolExecutor-0_3 在执行任务 15
144
ThreadPoolExecutor-0_0 在执行任务 16
196
169
ThreadPoolExecutor-0_2 在执行任务 17
ThreadPoolExecutor-0_1 在执行任务 18
225
ThreadPoolExecutor-0_3 在执行任务 19
256
324
289
361
这才是正确操作。