gevent 模块生成的 greenlet 对象,要如何启动?

发布于 2022-09-05 10:47:04 字数 2381 浏览 19 评论 0

以前以为:gevent 模块生成的 greenlet 对象,需要用 join 或 joinall 来启动。例如:

# /usr/bin/env python3
# -*- encoding:utf-8 -*-

from gevent import monkey; monkey.patch_all()
import gevent,urllib.request

def f(url):
    print('GET: %s' % url)
    resp = urllib.request.urlopen(url)
    data = resp.read()
    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
        gevent.spawn(f, 'https://www.python.org/'),
        gevent.spawn(f, 'https://www.yahoo.com/'),
        gevent.spawn(f, 'https://github.com/'),
])

但是有一次看到一个 “通过单线程实现多socket并发” 的例子:

服务端:

# /usr/bin/env python3
# -*- encoding:utf-8 -*-

import socket, gevent
from gevent import socket, monkey;monkey.patch_all()


def server(port):
    s = socket.socket()
    s.bind(('0.0.0.0', port))
    s.listen(500)
    while True:
        cli, addr = s.accept()
        gevent.spawn(handle_request, cli)


def handle_request(conn):
    try:
        while True:
            data = conn.recv(1024)
            print("recv:", data)
            conn.send(data)
            if not data:
                conn.shutdown(socket.SHUT_WR)

    except Exception as  ex:
        print(ex)
    finally:
        conn.close()


if __name__ == '__main__':
    server(8001)

客户端

# /usr/bin/env python3
# -*- encoding:utf-8 -*-

import socket

HOST = 'localhost'
PORT = 8001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
    msg = bytes(input(">>:"), encoding="utf8")
    s.sendall(msg)
    data = s.recv(1024)
    print('Received:',data.decode('utf-8'))

试着启动了一个服务端,多个客户端,与多个客户端的交互确实可以并行。但是服务端那里,只是生成了 greenlet 对象(gevent.spawn(handle_request, cli)),并没有 join 或 joinall,为什么也可以启动 spawn 生成的协程?

我又试着把第一个爬取网页的例子,去掉了 joinall ,像这样:

# /usr/bin/env python3
# -*- encoding:utf-8 -*-

# 第一个例子去掉 joinall ,结果并不执行

from gevent import monkey; monkey.patch_all()
import gevent,urllib.request

def f(url):
    print('GET: %s' % url)
    resp = urllib.request.urlopen(url)
    data = resp.read()
    print('%d bytes received from %s.' % (len(data), url))


gevent.spawn(f, 'https://www.python.org/')
gevent.spawn(f, 'https://www.yahoo.com/')
gevent.spawn(f, 'https://github.com/')

仅仅是 spawn 了3个协程对象,果然就不执行了,不解啊,为什么第一个爬取网页的例子没有 joinall 就不行,而第二个socket服务器的例子就不需要 joinall 啊

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陌伤ぢ 2022-09-12 10:47:04

因为它在一个 while True 里,永远也不会退出(就算是想 join 都没机会)。

顾名思义,spawn 就是启动了。join 只是等待它们结束而已。你不想等也是可以的,但是你直接退出的话它们也就都死掉了。

狠疯拽 2022-09-12 10:47:04

我猜是因为accept()执行的时候让出了CPU吧。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文