发布于2021-07-25 06:46 阅读(970) 评论(0) 点赞(10) 收藏(4)
1.死锁与递归锁
2.线程队列Queue
3.进程池和线程池
4.协程
5.greenlet模块
6.gevent模块
死锁与递归锁
import time
def eat1(lock1,lock2,name):
lock1.acquire()
print('%s谁抢到了筷子'%name)
time.sleep(1)
lock2.acquire()
print('%s:抢到面条'%name)
time.sleep(1)
print('开始吃')
time.sleep(1)
lock2.release()
print('面条放下了')
lock1.release()
def eat2(lock1,lock2,name):
lock1.acquire()
print('%s谁抢到了筷子' % name)
time.sleep(1)
lock2.acquire()
print('%s:抢到面条' % name)
time.sleep(1)
print('开始吃')
time.sleep(1)
lock2.release()
print('面条放下了')
lock1.release()
死锁:
是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,
若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,
这些永远在互相等待的进程称为死锁进程,如下就是死锁
from threading import Thread,Lock
if __name__ == '__main__':
lock1=Lock()
lock2=Lock()
for i in ['wkj','www','WKJ']:
t=Thread(target=eat1,args=(lock1,lock2,i))
t.start()
for i in ['QQQ','EEE','FFF']:
t=Thread(target=eat2,args=(lock1,lock2,i))
t.start()
解决方法:递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
递归锁:
from threading import Thread,RLock
if __name__ == '__main__':
lock1=RLock()
lock2=lock1
for i in ['wkj','www','WKJ']:
t=Thread(target=eat1,args=(lock1,lock2,i))
t.start()
for i in ['QQQ','EEE','FFF']:
t=Thread(target=eat2,args=(lock1,lock2,i))
t.start()
线程队列Queue
线程队列:
1.先进先出
2.后进先出
3.优先级队列
from queue import Queue, LifoQueue, PriorityQueue
if __name__ == '__main__':
# 1.先进先出
q = Queue()
q.put('ly is handsome1')
q.put('ly is handsome2')
print(q.get())
# 2. 后进先出 堆, 栈。, 队列, 链表,
q = LifoQueue()
q.put('ly is handsome1')
q.put('ly is handsome2')
print(q.get())
# 3.优先级队列
q = PriorityQueue()
q.put((20, 'a'))
q.put((10, 'b'))
q.put((30, 'c'))
print(q.get())
进程池和线程池
ThreadPoolExecutor:线程池,提供异步调用
ProcessPoolExecutor:进程池,提供异步调用
基本方法:
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):回调函数
done():判断某一个线程是否完成
cancle():取消某个任务
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
def task(n):
time.sleep(1)
return n + n
def call_back(res):
print(res.result())
if __name__ == '__main__':
urls = [1, 2, 3, 4]
p1 = ProcessPoolExecutor(3) # 里面有三个进程
p2 = ThreadPoolExecutor(3) # 里面有三个线程
for url in urls:
p1.submit(task, url).add_done_callback(call_back)
for url in urls:
p2.submit(task, url).add_done_callback(call_back)
print('ZJC')
协程
协程:是一种用户态的轻量级线程,由用户程序自己控制调度得的
强调:
1.python的线程属于内核级别的,即由操作系统控制调度
(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
2.单线程内开启协程,一旦遇到io,就会从应用程序级别
(而非操作系统)控制切换,以此来提升效率
(!!!非io操作的切换与效率无关)
优点:
1.协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
2.单线程内就可以实现并发效果,最大限度地利用cpu
缺点:
1.协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,
每个进程内开启多个线程,每个线程内开启协程
2.协程是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
特点:
1.必须在只有一个单线程里实现并发
2.修改共享数据不需加锁
3.用户程序里自己保存多个控制流的上下文栈
4.一个协程遇到IO操作自动切换到其它协程
greenlet模块
安装:pip3 install greenlet
greenlet只是提供了一种比generator更加便捷的切换方式,当切到一个任务执行时如果遇到io,那就原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。
单线程里的这20个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻塞,就利用阻塞的时间去执行任务2…如此,才能提高效率,这就用到了Gevent模块
from greenlet import greenlet
def eat(name):
print('%s:吃了一口'%name)
g2.switch(name)
print('%s:又吃了一口'%name)
g2.switch()
def play(name):
print('%s:玩了一下' % name)
g1.switch()
print('%s:又玩了一下' % name)
g1=greenlet(eat)
g2=greenlet(play)
g1.switch('wkj')
gevent模块
安装:pip3 install gevent
gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度
import time
import gevent
def eat(name):
print('%s:吃了一口'%name)
gevent.sleep(2)
print('%s:又吃了一口'%name)
def play(name):
print('%s:玩了一下' % name)
gevent.sleep(3)
print('%s:又玩了一下' % name)
ctime=time.time()
g1=gevent.spawn(eat,'wkj')
g2=gevent.spawn(play,'wkj')
g1.join()
g2.join()
print(time.time()-ctime)
猴子补丁
什么是猴子补丁?
1,这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)。
2,还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch。
名字听起来稀奇古怪的, 跟python的这个功能搭不上边。
拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)
这里有一个比较实用的例子,很多用到import json, 后来发现ujson性能更高,如果觉得把每个文件的import json改成import ujson as json成本较高, 或者说想测试一下ujson替换是否符合预期, 只需要在入口加上:
import json
import ujson
def monkey_patch_json():
json.__name__ = 'ujson'
json.dumps = ujson.dumps
json.loads = ujson.loads
monkey_patch_json()
aa=json.dumps({'name':'wkj','age':22})
print(aa)
原文链接:https://blog.csdn.net/weixin_42213824/article/details/119034148
作者:小可爱不要爱
链接:http://www.pythonpdf.com/blog/article/478/07dee487ce94315bdaaf/
来源:编程知识网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!