Justin-刘清政的博客

1-Python中的GIL

2020-03-25

一 猴子补丁

1.1 什么是猴子补丁?

  1,这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)。
  2,还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch。

  名字听起来稀奇古怪的, 跟python的这个功能搭不上边, 所以我们直接来说功能吧!

1.2 猴子补丁的功能(一切皆对象)

  1.拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)

1
2
3
4
5
6
7
8
9
10
11
class Monkey():
def play(self):
print('猴子在玩')

class Dog():
def play(self):
print('狗子在玩')
m=Monkey()
m.play()
m.play=Dog().play
m.play()

1.3 monkey patch的应用场景

这里有一个比较实用的例子,很多用到import json, 后来发现ujson性能更高,如果觉得把每个文件的import json改成import ujson as json成本较高, 或者说想测试一下ujson替换是否符合预期, 只需要在入口加上:

1
2
3
4
5
6
7
8
9
10
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':'lqz','age':19})
print(aa)

二 Gevent介绍

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

2.1 用法

1
2
3
4
5
6
7
8
9
10
11
12
#用法
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的

g2=gevent.spawn(func2)

g1.join() #等待g1结束

g2.join() #等待g2结束

#或者上述两步合作一步:gevent.joinall([g1,g2])

g1.value#拿到func1的返回值

2.2 示例1(遇到io自动切)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import gevent
def eat(name):
print('%s eat 1' %name)
gevent.sleep(2)
print('%s eat 2' %name)

def play(name):
print('%s play 1' %name)
gevent.sleep(1)
print('%s play 2' %name)


g1=gevent.spawn(eat,'lqz')
g2=gevent.spawn(play,name='lqz')
g1.join()
g2.join()
#或者gevent.joinall([g1,g2])
print('主')

2.3 示例二

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
'''
上例gevent.sleep(2)模拟的是gevent可以识别的io阻塞,

而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了

from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前

或者我们干脆记忆成:要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头
'''
from gevent import monkey;monkey.patch_all()

import gevent
import time
def eat():
print('eat food 1')
time.sleep(2)
print('eat food 2')

def play():
print('play 1')
time.sleep(1)
print('play 2')

g1=gevent.spawn(eat)
g2=gevent.spawn(play_phone)
gevent.joinall([g1,g2])
print('主')

# 我们可以用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程

2.4 单线程的套接字服务端并发

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

#
# from socket import socket
#
# from multiprocessing import Process
# from threading import Thread
#
# server=socket()
# server.bind(('127.0.0.1',8080))
# server.listen(5)
#
# def talk(conn):
# while True:
# try:
# data=conn.recv(1024)
# if len(data)==0:break
# print(data)
# conn.send(data.upper())
# except Exception as e:
# print(e)
# conn.close()
#
# while True:
# conn,addr=server.accept()
# # t=Process(target=talk,args=(conn,))
# t=Thread(target=talk,args=(conn,))
# t.start()





from gevent import monkey;monkey.patch_all()
import gevent
from socket import socket
# from multiprocessing import Process
from threading import Thread
def talk(conn):
while True:
try:
data=conn.recv(1024)
if len(data)==0:break
print(data)
conn.send(data.upper())
except Exception as e:
print(e)
conn.close()
def server(ip,port):
server = socket()
server.bind((ip, port))
server.listen(5)
while True:
conn,addr=server.accept()
# t=Process(target=talk,args=(conn,))
# t=Thread(target=talk,args=(conn,))
# t.start()
gevent.spawn(talk,conn)


if __name__ == '__main__':
g1=gevent.spawn(server,'127.0.0.1',8080)
g1.join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


import socket
from threading import current_thread,Thread
def socket_client():
cli=socket.socket()
cli.connect(('127.0.0.1',8080))
while True:
ss='%s say hello'%current_thread().getName()
cli.send(ss.encode('utf-8'))
data=cli.recv(1024)
print(data)

for i in range(500):
t=Thread(target=socket_client)
t.start()

三 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
import threading
import asyncio

@asyncio.coroutine
def hello():
print('Hello world! (%s)' % threading.currentThread())
yield from asyncio.sleep(1)
print('Hello again! (%s)' % threading.currentThread())

loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

# 3.5以后

import threading
import asyncio
import time
async def hello():
print('Hello world! (%s)' % threading.currentThread())
await asyncio.sleep(2)
print('Hello again! (%s)' % threading.currentThread())

loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
Tags: Python
使用支付宝打赏
使用微信打赏

点击上方按钮,请我喝杯咖啡!

扫描二维码,分享此文章