线程队列里面有几种有意思的算法模型,好比队列,堆栈,以及有优先级的取数据,是比较好玩的几个东西.实例见下面:html
xxxxxxxxxx
import queue
# 队列:先进先出
q = queue.Queue()
q.put('123')
q.put('456')
print(q.get())
print(q.get())
'''
123
456
Process finished with exit code 0
能够看到,程序到此已经结束,其取数据的顺序就是先进先出
比较有趣的是,队列里面还有task_done和join两个方法,其用法和以前所了解的JoinableQueue里面的task_done和join是彻底同样的,即有几个put就要有几个task_done,否则join就会卡主,不会释放程序
'''
q.task_done()
# q.task_done()
q.join()# 这里就会卡主,程序不会继续向下执行,也不会自动结束
'''
123
456
'''
xxxxxxxxxx
import queue
# 堆栈,先进后出
q = queue.LifoQueue()
q.put('123')
q.put('456')
q.put('789')
print(q.get())
print(q.get())
print(q.get())
'''
结果:
789
456
123
'''
xxxxxxxxxx
import queue
# 能够根据优先级取数据
q = queue.PriorityQueue()
# 这里要注意,put里面的第一个参数一般为int类型,并且值越小优先级越高,包括负数,意思就是全部的负数优先级都高于整数,
q.put((-1, 'a'))
q.put((80, 'b'))
q.put((1, 'c'))
print(q.get())
print(q.get())
'''
结果为:
(-1, '1')
(1, '3')
(80, '2')
Process finished with exit code 0
'''
定时器,顾名思义,就是定时的意思,咱们设定一个延时,就可让进程延时这些时间而后再开启.实例以下:node
xxxxxxxxxx
from threading import Thread, current_thread, Timer
import time
def task():
end = time.time()
print(f'线程执行了')
time.sleep(2)
print(f'线程结束了')
print(f'进程开启延时了{end - start:6.2f}秒')
if __name__ == '__main__':
start = time.time()
t = Timer(4, task) # Timer()括号里第一个参数为延时的时间,第二个为开启的线程要运行的函数,这个例子是过4秒后开启一个线程
t.start()
'''
执行结果为:
线程执行了
线程结束了
进程开启延时了 4.00秒
Process finished with exit code 0
到这里咱们可能会有个疑问,那么这种延时和直接用time.sleep()有什么区别呢?
区别就在于time.sleep()是整个程序都暂停了,而Timer只是延时开启进程,对于别的代码的运行没有任何影响,咱们能够在main程序里面加入两个print来证实这一点
'''
from threading import Thread, current_thread, Timer
import time
def task():
end = time.time()
print(f'线程执行了')
time.sleep(2)
print(f'线程结束了')
print(f'进程开启延时了{end - start:6.2f}秒')
if __name__ == '__main__':
print('进入main')
start = time.time()
print('准备进入延时')
t = Timer(4, task)
t.start()
print('main结束')
'''
执行结果为:
进入main
准备进入延时
main结束
线程执行了
线程结束了
进程开启延时了 4.00秒
Process finished with exit code 0
上面的执行结果咱们就能够看出,延时并无影响其他代码的运行,这点很是难得
'''
首先咱们要明白进程池和线程池的概念是什么,所谓池,池子,现实生活中是盛水的,能够说是一个容器,在咱们的Python里面也是一个容器,用来容纳进程或者线程.python
那么进程池/线程池的做用就是,当计算机须要并发的任务量远远大于计算机所能承受的范围的时候,或者说计算机没法一次性开启过多的任务数的时候,咱们就须要进程池/线程池来限制当前计算机的进程数/线程数,从而保护计算机,或者是服务器,使其不至于宕机,影响业务.web
池所用的模块是ProcessPoolExecutor和 ThreadPoolExecutor,经常使用的一些方法包括:算法
result()
,等待该进程/线程的返回结果,当结果都返回以后,result()才会打印出来而后执行后面的代码,这样会致使全部的任务变成串行,一个线程执行完才会去执行下一个线程,虽然下降了效率,可是提升了程序的安全性,条理性也会更清楚编程
submit(obj,*args,**kwargs)
第一个参数就是所调用的函数名,第二个和第三个都是调用的函数所须要传入的参数,submit会有一个返回值,因此一般所调用的函数会有返回值,来做为submit的返回值.windows
shutdown()
关闭当前进程池/线程池安全
例程以下:服务器
xxxxxxxxxx
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time
def task(i):
print(f'开启{i}')
print(f'线程{currentThread().name}执行任务{i}')
# print(f'进程{current_process().name}执行任务{i}')
time.sleep(2)
print(f'线程{currentThread().name}结束任务{i}')
print(f"\033[5;31;40m结束{i}\033[0m")
return i ** 2
# print(f'进程{current_process().name}结束任务{i}')
if __name__ == '__main__':
# pool_p = ProcessPoolExecutor(4)
pool_t = ThreadPoolExecutor(4)
fu_list = []
for i in range(5):
# submit括号里第一个参数是所调用的函数名task,第二个和第三个是须要传入的调用函数task的形参,
# submit能够返回一个对象,因此能够在task函数里面写返回值
future = pool_t.submit(task, i) # 5个线程,解决20个任务
print(f'执行结果为{future.result()}')
# 若是没有结果,会一直等待拿到结果,就会致使全部的任务变成串行,一个线程运行完才会运行下一个任务
# pool_p.submit(task, i)
pool_t.shutdown() # 会关闭池的入口,会等到全部的任务执行完,结束阻塞
for fu in fu_list:
print(fu.result())
'''
开启0
线程ThreadPoolExecutor-0_0执行任务0
线程ThreadPoolExecutor-0_0结束任务0
结束0
执行结果为0
开启1
线程ThreadPoolExecutor-0_0执行任务1
线程ThreadPoolExecutor-0_0结束任务1
结束1
执行结果为1
开启2
线程ThreadPoolExecutor-0_1执行任务2
线程ThreadPoolExecutor-0_1结束任务2
结束2
执行结果为4
开启3
线程ThreadPoolExecutor-0_0执行任务3
线程ThreadPoolExecutor-0_0结束任务3
结束3
执行结果为9
开启4
线程ThreadPoolExecutor-0_2执行任务4
线程ThreadPoolExecutor-0_2结束任务4
结束4
执行结果为16
Process finished with exit code 0
'''
同步和异步实际上是提交任务的两种方式,简单来讲,并发
简单来讲:协程是一种用户态的轻量级的线程,是由用户程序本身控制调度的
协程须要注意的两点是:
为了正确的使用协程,咱们须要引入gevent模块(这个不是Python自带的模块,须要读者本身下载,指令pip3 install gevent),并且须要使用到gevent的一个很是有趣的魔法方法,叫作moncky,具体见下例
xxxxxxxxxx
from gevent import monkey;monkey.patch_all() # 咱们须要在开头加上这一句,由于gevent自己并不能捕获全部的IO,只能识别自身的延时,因此这个语句至关于一个补丁,能够识别程序里面全部的IO,而后遇到这些IO的时候切换至其余的协程
import gevent# 导入gevent模块,这个导入必定要在上面的语句下面,切记!
import time
def eat():
print('eat 1')
time.sleep(2)
print('eat 2')
def play():
print('play 1')
time.sleep(3)
print('play 2')
start = time.time()
g1 = gevent.spawn(eat)# gevent的用法不一样于以前学习的进程和线程,是另外一种调用方法,并且下面必定须要用join来阻塞才能得到每一个协程的执行结果,不然程序不会返回任何值,也不会执行开启协程所写入的那个任务的内容
g2 = gevent.spawn(play)
g1.join()
g2.join()
end = time.time()
print(f'{end - start:6.6f}')