Gunicorn 服务器中使用的内置 Python 的 next 函数如何工作

问题描述 投票:0回答:1

以下是

gunicorn.workers.sync.SyncWorker
self.handle
方法的代码横截面:

def handle(self, listener, client, addr):
        req = None
        try:
            if self.cfg.is_ssl:
                client = sock.ssl_wrap_socket(client, self.cfg)
            parser = http.RequestParser(self.cfg, client, addr)
            req = next(parser)
            self.handle_request(listener, req, client, addr)

上面的方法执行行:

parser = http.RequestParser(self.cfg, client, addr)
,它返回一个继承自
gunicorn.http.parser.RequestParser
gunicorn.http.parser.Parser
对象,如下所示:

class Parser(object):

    mesg_class = None

    def __init__(self, cfg, source, source_addr):
        self.cfg = cfg
        if hasattr(source, "recv"):
            self.unreader = SocketUnreader(source)
        else:
            self.unreader = IterUnreader(source)
        self.mesg = None
        self.source_addr = source_addr

        # request counter (for keepalive connetions)
        self.req_count = 0

    def __iter__(self):
        return self

    def __next__(self):
        # Stop if HTTP dictates a stop.
        if self.mesg and self.mesg.should_close():
            raise StopIteration()

        # Discard any unread body of the previous message
        if self.mesg:
            data = self.mesg.body.read(8192)
            while data:
                data = self.mesg.body.read(8192)

        # Parse the next request
        self.req_count += 1
        self.mesg = self.mesg_class(self.cfg, self.unreader, self.source_addr, self.req_count)
        if not self.mesg:
            raise StopIteration()
        return self.mesg

    next = __next__

上面的对象

gunicorn.http.parser.Parser
定义了
self.__iter__
self__next__
特殊方法,是
iterables
iterators
的协议。然而,在方法
parser
中定义的保存返回对象的局部变量
self.handle
gunicorn.http.parser.RequestParser
的实例,而不是
iterator
,正如
pdb
的输出所证实的那样(参见下面的 stracktrace)调试器:
<class 'gunicorn.http.parser.RequestParser'>
。在已分配给
parser
的返回对象之后,该方法执行行:
req = next(parser)
,并传递
parser
作为其参数。

问题:

内置函数

next()
不应该接受第一个参数作为迭代器吗?
parser
不是
iterator
,而是
gunicorn.http.parser.RequestParser
类的实例。以下是
next()
的Python文档:

next(iterator)
next(iterator, default)
Retrieve the next item from the iterator by calling its __next__() method. If default is given, it is returned if the iterator is exhausted, otherwise StopIteration is raised.

我已经运行

pdb
来生成堆栈跟踪,以确认当
req=next(parser)
行执行时实际发生的情况。它落入
self.__next__
的方法
gunicorn.http.parser.Parser
。应该返回
self.__iter__
的方法
iterator
根本没有被调用,实际上我将其从代码中注释掉了,代码运行起来没有任何复杂性。
self.__iter__
这个方法到底是必需的吗?

堆栈跟踪:

/home/humbulani/django/env/bin/gunicorn(8)<module>()
-> sys.exit(run())
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/app/wsgiapp.py(71)run()
-> WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/app/base.py(264)run()
-> super().run()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/app/base.py(74)run()
-> Arbiter(self).run()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/arbiter.py(226)run()
-> self.manage_workers()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/arbiter.py(602)manage_workers()
-> self.spawn_workers()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/arbiter.py(673)spawn_workers()
-> self.spawn_worker()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/arbiter.py(640)spawn_worker()
-> worker.init_process()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/workers/base.py(144)init_process()
-> self.run()
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/workers/sync.py(126)run()
-> self.run_for_one(timeout)
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/workers/sync.py(70)run_for_one()
-> self.accept(listener)
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/workers/sync.py(32)accept()
-> self.handle(listener, client, addr)
  /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/workers/sync.py(140)handle()
-> req = next(parser) # self.msg attribute
> /home/humbulani/django/env/lib/python3.10/site-packages/gunicorn/http/parser.py(37)__next__()
-> if self.mesg and self.mesg.should_close():

我们将非常感谢您的回复。

python iterator gunicorn iterable built-in
1个回答
0
投票

next
作用很少;你可以想象它的实现是这样的:

_sentinel = object()

def next(itr, default=_sentinel):
    try:
        return itr.__next__()
    except StopIteration:
        if default is _sentinel:
            raise
        return default

所以

next(parser)
只是调用
parser.__next__
,因为
parser
是一个迭代器:它是定义
Parser
的类 (
__next__
) 的实例。

next
接受的是一个不是迭代器的类的实例。通过定义
__iter__
Parser
恰巧 also(像所有其他迭代器一样)是一个 iterable。您可以成为可迭代对象而不是迭代器(如
list
),但反之则不然。

© www.soinside.com 2019 - 2024. All rights reserved.