05:死锁问题 --- 协程

1 死锁问题(递归锁,可重入锁)

 

 

 

1 所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁


2 可重入锁,递归锁
# from threading import Thread, Lock
# import time
# import random
#
#
# def eat1(lock_1, lock_2, name):
#     lock_1.acquire()
#     print('%s:拿到了筷子' % name)
#     time.sleep(random.random())
#     lock_2.acquire()
#     print('%s:拿到了面条' % name)
#     print('开始吃面')
#     time.sleep(random.random())
#     lock_2.release()
#     print('%s放下了面条' % name)
#     lock_1.release()
#     print('%s放下了筷子' % name)
#
#
# def eat2(lock_1, lock_2, name):
#     lock_2.acquire()
#     print('%s:拿到了面条' % name)
#     time.sleep(random.random())
#     lock_1.acquire()
#     print('%s:拿到了筷子' % name)
#     print('开始吃面')
#     time.sleep(random.random())
#     lock_1.release()
#     print('%s放下了筷子' % name)
#     lock_2.release()
#     print('%s放下了面条' % name)
#
#
# if __name__ == '__main__':
#     lock_1 = Lock()
#     lock_2 = Lock()
#     for i in ['张三', '李四', '王五']:
#         t = Thread(target=eat1, args=[lock_1, lock_2, i])
#         t.start()
#     for i in ['赵6', '往7', '傻逼']:
#         t = Thread(target=eat2, args=[lock_1, lock_2, i])
#         t.start()
​
​
​
### 解决死锁问题  RLock:可重入,可以重复acquire,获得几次,就要释放几次
from threading import Thread, Lock,RLock
import time
import random
​
​
def eat1(lock_1, lock_2, name):
    lock_1.acquire()
    print('%s:拿到了筷子' % name)
    time.sleep(random.random())
    lock_2.acquire()
    print('%s:拿到了面条' % name)
    print('开始吃面')
    time.sleep(random.random())
    lock_2.release()
    print('%s放下了面条' % name)
    lock_1.release()
    print('%s放下了筷子' % name)
​
​
def eat2(lock_1, lock_2, name):
    lock_2.acquire()
    print('%s:拿到了面条' % name)
    time.sleep(random.random())
    lock_1.acquire()
    print('%s:拿到了筷子' % name)
    print('开始吃面')
    time.sleep(random.random())
    lock_1.release()
    print('%s放下了筷子' % name)
    lock_2.release()
    print('%s放下了面条' % name)
​
​
if __name__ == '__main__':
    lock_1 = RLock()
    lock_2 = lock_1
​
    # lock_1 = Lock()
    # lock_2 = lock_1
    for i in ['张三', '李四', '王五']:
        t = Thread(target=eat1, args=[lock_1, lock_2, i])
        t.start()
    for i in ['赵6', '往7', '傻逼']:
        t = Thread(target=eat2, args=[lock_1, lock_2, i])
        t.start()

 


2 线程队列

 

 

1 线程Queue,解决线程间数据共享的问题
2 线程间数据共享可以使用共享变量(可能会存在并发安全的问题)
from threading import Thread
from queue import Queue,LifoQueue,PriorityQueue # 线程queue
# Queue:先进先出
#LifoQueue:后进先出
#PriorityQueue:优先级队列
​
​
​
​
# import time
# def task(queue):
#     time.sleep(3)
#     queue.put('lqz')
#
#
#
# if __name__ == '__main__':
#     queue=Queue()
#     t=Thread(target=task,args=[queue,])
#     t.start()
#
#
#     res=queue.get()
#     print(res)
​
​
# Queue:先进先出
# LifoQueue:后进先出
# PriorityQueue:优先级队列
​
​
if __name__ == '__main__':
    # quque1=Queue()
    #
    # quque1.put(1)
    # quque1.put(2)
    # print(quque1.get())
​
​
​
    # quque2=LifoQueue()
    # quque2.put(1)
    # quque2.put(2)
    # print(quque2.get())
​
​
    quque3=PriorityQueue()
    quque3.put((1,'lqz'))
    quque3.put((100,'egon'))
    # 数字越小,优先级越高
    print(quque3.get())

 


3 进程池,线程池(重点)

 

 

# 线程池,进程池都在这个模块下concurrent.futures
​
​
import time
import os
​
import random
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
​
# def task(n):
#     print(os.getpid(), '开始执行了')
#     time.sleep(random.random())
#     return n * n
#
#
#
# def callback(result):
#     print(result)
# if __name__ == '__main__':
#     # 开进程池去执行
#     # ProcessPoolExecutor实例化得到一个对象
#     pool_p=ProcessPoolExecutor(3)
#     # ll=[]
#     # for i in range(10):
#     #     # 把任务提交到进程池执行
#     #     f=pool_p.submit(task,n=i)
#     #     ll.append(f)
#     #
#     # # 等待所有子进程执行完成,主进程在执行
#     # pool_p.shutdown()
#     #
#     # for l in ll:
#     #     res=l.result()  # 取到当前进程执行任务的返回值
#     #     print(res)
#     #
#     # print('我是主进程')
#
#     # map取代for循环的,第一个参数是要执行的任务,第二个参数,是一个可迭代对象,迭代一次的结果,会传给任务
#
#
#
#     #   for i in range(10):
#     #     f=pool_p.submit(task,n=i)
#     # 等同于上面
#     # pool_p.map(task,range(10))
#     # pool_p.shutdown()
#     # print('主进程')
#
#
#     ## 回调
#     for i in range(10):
#         pool_p.submit(task,n=i).add_done_callback()
​
​
def task(n):
    print(os.getpid(), '开始执行了')
    time.sleep(1)
    return n * n
​
​
def callback(result):
    print(result.result())
​
​
 if __name__ == '__main__':
    pool_p = ProcessPoolExecutor(3)
    for i in range(10):
        pool_p.submit(task, n=i).add_done_callback(callback)
​
'''
​
submit
shutdown
result
map(了解)
add_done_callback:回调
​
'''

 



4 协程介绍

1 协程是:程序级别的切换,单线程下实现并发
python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)


5 greenlet模块(初级模块,实现了保存状态加切换)

 

 

# 安装第三方模块:在命令行下
# pip3 install greenlet
# pip3 uninstall greenlet  卸载第三方模块
# pip3 list   # 列出当前解释器环境下安装的第三方模块
​
​
from greenlet import greenlet
​
​
​
def eat(name):
    print(name,'在吃了一口')
    g2.switch(name)
​
    print(name,'在吃了第二口')
    g2.switch()
​
​
def play(name):
    print(name, '玩了一下')
    g1.switch()
​
    print(name, '玩了第二下')
​
​
g1=greenlet(eat)
g2=greenlet(play)
​
g1.switch('egon')
​
​
### 写两个task,一个计算从1+1w,另一个计算从1乘以到1w,统计一下,切换执行时间快还是不切换快

 

6 gevent模块

## gevent模块,协程模块,遇到io可以自动切换
​
​
# pip3 install gevent
import gevent
import time
​
# def eat(name):
#     print(name, '在吃了一口')
#     # 遇到了io
#     gevent.sleep(2)
#
#     print(name, '在吃了第二口')
#
#
# def play(name):
#     print(name, '玩了一下')
#     # 遇到了io,是gevent的io
#     gevent.sleep(3)
#     print(name, '玩了第二下')
#
#
# res1 = gevent.spawn(eat, 'egon')
# res2 = gevent.spawn(play, 'egon')
#
#
# ctime=time.time()
# # res1.join()
# # res2.join()  # 等地任务执行完成再执行下面那句
#
# gevent.joinall([res1,res2])   # 相当于上面那两句
# print('主线程')
# print(time.time()-ctime)
​
​
​
​
###使用原来的time的io,不会切,并且变成了串行
# def eat(name):
#     print(name, '在吃了一口')
#     time.sleep(2)
#
#     print(name, '在吃了第二口')
#
#
# def play(name):
#     print(name, '玩了一下')
#     time.sleep(3)
#     print(name, '玩了第二下')
#
#
# res1 = gevent.spawn(eat, 'egon')
# res2 = gevent.spawn(play, 'egon')
#
#
# ctime=time.time()
#
# gevent.joinall([res1,res2])   # 相当于上面那两句
# print('主线程')
# print(time.time()-ctime)
​
​
### time的io也要切换
# 猴子补丁:把原来的io全都替换成gevent的io
from gevent import monkey;monkey.patch_all()
​
​
​
def eat(name):
    print(name, '在吃了一口')
    time.sleep(2)
​
    print(name, '在吃了第二口')
​
​
def play(name):
    print(name, '玩了一下')
    time.sleep(3)
    print(name, '玩了第二下')
​
​
res1 = gevent.spawn(eat, 'egon')
res2 = gevent.spawn(play, 'egon')
​
​
ctime=time.time()
​
gevent.joinall([res1,res2])   # 相当于上面那两句
print('主线程')
print(time.time()-ctime)

 

7 asyncio

 

 

# 内置模块   python 3.4 推出这个模块,python作者主导的
import asyncio
import time
import threading
# 这个函数是协程函数
async def task():
    res=threading.current_thread().getName()
    print(res)
    print('xxx')
    await asyncio.sleep(2)
    print('协程执行完成')

async def task2():
    res=threading.current_thread().getName()
    print(res)
    print('2222')
    await asyncio.sleep(3)
    print('222协程执行完成')



ctime=time.time()
loop=asyncio.get_event_loop()



tasks=[task(),task2()]



loop.run_until_complete(asyncio.wait(tasks))
loop.close()
print(time.time()-ctime)

 

 

 

 



posted @ 2021-04-26 20:54  Jerry`  阅读(308)  评论(0编辑  收藏  举报