day33 GIL锁 线程队列 线程池

1.    全局解释器锁GIL

Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
  对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。

  在多线程环境中,Python 虚拟机按以下方式执行:

  a、设置 GIL;

  b、切换到一个线程去运行;

  c、运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0));

  d、把线程设置为睡眠状态;

  e、解锁 GIL;

  d、再次重复以上所有步骤。
  在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。

2.   线程队列

queue队列 :使用import queue,用法与进程Queue一样

queue is especially useful in threaded programming when information must be exchanged safely between multiple threads.

class queue.Queue(maxsize=0) #先进先出
import queue
#先进先出型
q=queue.Queue(3)
q.put(3)
q.put(2)
q.put(1) print(q.get())
print(q.get())
print(q.get()) """
结果
3
2
1
"""

先进先出型

class queue.LifoQueue(maxsize=0) #last in fisrt out

import queue

q=queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3) print(q.get())
print(q.get())
print(q.get())
"""
结果
3
2
1 """

先进后出行

class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

import queue

q=queue.PriorityQueue()
#put进入一个元组,元组的第一个元素一般是优先级(一般是数字,也可以是非数字),数字越小,优先级越小
q.put((-1,"a"))
q.put((0,"b"))
q.put((10,"c"))
q.put((20,"d")) print(q.get())
print(q.get())
print(q.get())
print(q.get()) """
结果
数字越小,优先级越高,越优先输出
(-1, 'a')
(0, 'b')
(10, 'c')
(20, 'd') """

优先级队列

注:优先级相同的会根据第二元素比较,第二个元素是根据编码的顺序比较,并且第二个元素的类型必须一致并且,是有序的才可以比较

如果两个值的优先级一样,那么按照后面的值的acsii码顺序来排序,如果字符串第一个数元素相同,比较第二个元素的acsii码顺序

TypeError: unorderable types: dict() < dict() 不能是字典

优先级相同的两个数据,他们后面的值必须是相同的数据类型才能比较,可以是元祖,也是通过元素的ascii码顺序来排序

3.    Python标准模块--concurrent.futures

#1 介绍
concurrent.futures模块提供了高度封装的异步调用接口
ThreadPoolExecutor:线程池,提供异步调用
ProcessPoolExecutor: 进程池,提供异步调用
Both implement the same interface, which is defined by the abstract Executor class. #2 基本方法
#submit(fn, *args, **kwargs)
异步提交任务 #map(func, *iterables, timeout=None, chunksize=1)
取代for循环submit的操作 #shutdown(wait=True)
相当于进程池的pool.close()+pool.join()操作
wait=True,等待池内所有任务执行完毕回收完资源后才继续
wait=False,立即返回,并不会等待池内的任务执行完毕
但不管wait参数为何值,整个程序都会等到所有任务执行完毕
submit和map必须在shutdown之前 #result(timeout=None)
取得结果 #add_done_callback(fn)
回调函数
import time,random
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def func(n):
time.sleep(random.randint(1,3))
return n*n if __name__ == '__main__':
p=ProcessPoolExecutor(max_workers=4)
list=[]
for i in range(10):
ret=p.submit(func,i)
list.append(ret)
print(ret.result())
p.shutdown()
for ret in list:
print(ret.result())
from concurrent.futures import ThreadPoolExecutor

def func(n):
return n**2 if __name__ == '__main__':
t_p=ThreadPoolExecutor(max_workers=4)
list=[]
for i in range(10):
ret=t_p.submit(func,i)#异步提交任务
list.append(ret)
# print(ret.result()) #等待任务提交之后拿去结果,拿不到就柱塞,拿到了就继续 t_p.shutdown()
print("主进程结束")
for ret in list:
print(ret.result())

ThreadPoolExecutor

from concurrent.futures import ThreadPoolExecutor

def func(n):
return n*n
if __name__ == '__main__':
t_p=ThreadPoolExecutor(max_workers=4) # for i in range(10):
# t_p.submit(func,i)
t_p.map(func,range(10)) #map取代了for+submit

map的用法

from concurrent.futures import ThreadPoolExecutor

def get(n):
return n*n
def call(m):
print(">>",m)
print(m.result()) if __name__ == '__main__':
t_p=ThreadPoolExecutor(max_workers=4) for i in range(3):
t_p.submit(get,i).add_done_callback(call) """
结果
>> <Future at 0x294c1d0 state=finished returned int> #必须.result才能拿到结果
0
>> <Future at 0x294c1d0 state=finished returned int>
1
>> <Future at 0x294c1d0 state=finished returned int>
4
"""
上一篇:redis 主从配置实例、注意事项、及备份方式


下一篇:CentOS7系统下GitLab的安装、汉化、修改默认端口、开启发送邮箱