死锁问题与协程

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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()

线程队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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())

进程池,线程池(重点)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 线程池,进程池都在这个模块下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:回调
'''

协程介绍

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 安装第三方模块:在命令行下
# 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,统计一下,切换执行时间快还是不切换快

gevent模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
## 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)

asyncio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 内置模块   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)