设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

gevent:轻松异步I/O

2014-9-3 09:33| 发布者: joejoe0332| 查看: 6181| 评论: 0|原作者: gones945, FreeZ|来自: oschina

摘要: 有些奇怪monkey.patch_all()的调用?不用担心,这可不像你每天打的猴子补丁(译注:monkey patching,即动态修改执行代码)。这仅仅是Python发行版恰好要打的一组猴子补丁。 ...

介绍


  gevent是一个使用完全同步编程模型的可扩展的异步I/O框架。


  让我们先来看一些示例,这里有一个 echo 服务器:

1
2
3
4
5
6
7
8
9
from gevent.server import StreamServer
 
def connection_handler(socket, address):
    for in socket.makefile('r'):
        socket.sendall(l)
 
if __name__ == '__main__':
    server = StreamServer(('0.0.0.0'8000), connection_handler)
    server.serve_forever()


  在这个例子中,我们并行发出100个web请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
from gevent import monkey
monkey.patch_all()
 
import urllib2
from gevent.pool import Pool
 
def download(url):
    return urllib2.urlopen(url).read()
 
if __name__ == '__main__':
    urls = ['http://httpbin.org/get'* 100
    pool = Pool(20)
    print pool.map(download, urls)


  有些奇怪monkey.patch_all()的调用?不用担心,这可不像你每天打的猴子补丁(译注:monkey patching,即动态修改执行代码)。这仅仅是Python发行版恰好要打的一组猴子补丁。


  最后一个例子是一个聊天服务器:

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
import gevent
from gevent.queue import Queue
from gevent.server import StreamServer
 
users = {}  # mapping of username -> Queue
 
 
def broadcast(msg):
    msg += '\n'
    for in users.values():
        v.put(msg)
 
 
def reader(username, f):
    for in f:
        msg = '%s> %s' % (username, l.strip())
        broadcast(msg)
 
 
def writer(q, sock):
    while True:
        msg = q.get()
        sock.sendall(msg)
 
 
def read_name(f, sock):
    while True:
        sock.sendall('Please enter your name: ')
        name = f.readline().strip()
        if name:
            if name in users:
                sock.sendall('That username is already taken.\n')
            else:
                return name
 
 
def handle(sock, client_addr):
    = sock.makefile()
 
    name = read_name(f, sock)
 
    broadcast('## %s joined from %s.' % (name, client_addr[0]))
 
    = Queue()
    users[name] = q
 
    try:
        = gevent.spawn(reader, name, f)
        = gevent.spawn(writer, q, sock)
        gevent.joinall([r, w])
    finally:
        del(users[name])
        broadcast('## %s left the chat.' % name)
 
 
if __name__ == '__main__':
    import sys
    try:
        myip = sys.argv[1]
    except IndexError:
        myip = '0.0.0.0'
 
    print 'To join, telnet %s 8001' % myip
    = StreamServer((myip, 8001), handle)
    s.serve_forever()


  够简单吧?让我们看看用gevent为什么要这样写。


同步 I/O

  同步I/O是指每个I/O操作被允许阻塞,直到它完成。 

 

  为了在同一时间扩展用户规模,我们需要的线程和进程。每个线程或进程被允许单独阻塞等待I/O操作。因为我们有完整的并发性,这阻塞不影响其他操作;从每个线程/进程的角度看,世界将停止直到操作完成。当结果准备就绪时,操作系统会恢复线程/进程。 






 

  线程的缺点:糟糕的性能。请参阅 Dave Beazley 的 GIL 笔记。还有高内存使用。线程在Linux中分配堆栈内存(请参阅ulimit -s)。这是对 Python 是没有用的 —— 相对较少线程就会让你耗尽内存。


  进程的缺点:没有共享的内存空间。还有高内存使用,因为堆栈分配和写入时复制(译注:copy-on-write)。线程在Linux中就像一种特殊的进程;内核结构都或多或少是相同的。



酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部