GIL锁,线程池

内容梗概:
1.线程队列
2.线程池
3.GIL锁


1.线程队列
1.1先进先出队列(FIFO)
import queue
q = queue.Queue(3)
q.put(1)
q.put(2)
q.put(3)
try:
q.put_nowait(3)
except queue.Full:
print("放满啦")
print(q.get())
print(q.get())
print(q.get())
try:
q.get_nowait()
except queue.Empty:
print("被掏空啦")


2. 1后进先出队列(LIFO)
import queue
q = queue.LifoQueue(3)
q.put(1)
q.put(2)
q.put(3)
try:
q.put_nowait(3)
except queue.Full:
print("放满啦")
print(q.get())
print(q.get())
print(q.get())
try:
q.get_nowait()
except queue.Empty:
print("被掏空啦")

1.3 优先级队列
import queue
q = queue.PriorityQueue(3)
q.put((1,11))
q.put((3,33))
q.put((2,22))

try:
q.put_nowait((4,44))
except Exception:
print("放满啦")
print(q.get())
print(q.get())
print(q.get())
try:
q.get_nowait()
except queue.Empty:
print("被掏空啦")


2.线程池
2.1 线程池的使用以及进程池创建区别
import time
from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
#
def func(n):
time.sleep(1)
return n * n
if __name__ == '__main__':
t_p = ThreadPoolExecutor(max_workers=4) # 线程池
# t_p = ProcessPoolExecutor(max_workers=4) # 进程池
res_lis = []
for i in range(10):
res = t_p.submit(func,i) #异步提交
res_lis.append(res)

t_p.shutdown() #相当于close+join 要等子线程跑完再做下一步

for el in res_lis:
# time.sleep(0.2)
print(el.result())

创建进程的另一种方法(也可用此种方法创建进程)
p_pool = Pool(4)
for i in range(10):
res = p_pool.apply_async(func,args=(i,))
print(res.get())

2.2 进程池的map方法
import time
from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

def func(n):
time.sleep(0.5)
return n * n

if __name__ == '__main__':
t_p = ThreadPoolExecutor(max_workers=4)

res = t_p.map(func, range(10)) #注意和进程池相比,此处Map没有自带close,join需要添加 shutdown()
t_p.shutdown()

for i in res:
time.sleep(0.5)
print(i)
print('主线程结束')

2.3 进程池的回调函数

import time
from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

def func(n):
time.sleep(0.5)
return n * n
def func1(n):
num = n.result()-1
print(num)

if __name__ == '__main__':
t_p = ThreadPoolExecutor(max_workers=4)
t_p.submit(func,5).add_done_callback(func1)


3.GIL锁
GIL: Global Interpreter Lock 全局变量锁

注意:1.GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。
2.在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势(每个进程内都有1个GIL锁,每个线程要争抢GIL锁来拿到解释器的使用权限)
3.GIL并不是Python的特性,Python完全可以不依赖于GIL,只是由于CPython由于历史原因暂时无法摆脱GIL
4.GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理(保护不同的数据的安全,就应该加不同的锁)

提问:GIL的存在,同一时刻同一进程中只有一个线程被执行,进程可以利用多核,但是开销大,而python的多线程开销小,但却无法利用多核优势,那PYTHON不是白学了?

1.对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用,当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),
这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,从而进一步分析python的多线程到底有无用武之地
2.现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

总结
应用:
    多线程用于IO密集型,如socket,爬虫,web
 多进程用于计算密集型,如金融分析





posted @ 2018-12-04 08:44  Mixtea  阅读(154)  评论(0编辑  收藏  举报