【问题标题】:How make an async RequestHandler in tornado python如何在龙卷风 python 中创建异步 RequestHandler
【发布时间】:2015-08-15 20:03:46
【问题描述】:

目前我正在使用 tornado 开发我的后端网络服务器。

我现在遇到的问题:
- 当发出请求并且服务器正在处理该请求时,所有其他请求都被阻止

我的请求处理程序:

class UpdateServicesRequestHandler( RequestHandler ):

    @gen.coroutine
    def get( self ):

        update = ServiceUpdate()
        response = yield update.update_all( )

        if self.request.headers.get('Origin'):
            self.set_header( 'Access-Control-Allow-Origin', self.request.headers.get('Origin') )
        self.set_header( 'Content-Type', 'application/json')
        self.write( response )

我的update_all()

@gen.coroutine
def update_all( self ):

    for service in self.port_list:
        response = yield self.update_service( str( service.get( 'port' ) ) )
        self.response_list.append( response )

    self.response = json.dumps( self.response_list )

    return self.response

我的update_sevice()

process = Popen( [ command ], stdout=PIPE, stderr=PIPE, shell=True )
output, error = process.communicate()

问题是,我需要update_all() 方法的结果。 那么是否有可能使这个请求不会阻塞我的整个服务器的请求?

谢谢!

【问题讨论】:

  • update.update_all() 是协程吗?它是否使用非阻塞 I/O 来完成其工作?
  • 刚刚更新了我的帖子..
  • 现在我们需要知道update_service 的样子。 :) 最终,我们需要知道您是否在 update_all 内部某处进行了缓慢的阻塞呼叫。
  • 我正在使用子进程process = Popen( [ command ], stdout=PIPE, stderr=PIPE, shell=True ) 运行生成的命令。通常我在几个目录上调用“git pull”命令
  • 你是在等待Popen 命令完成吗?因为那肯定会阻塞事件循环。

标签: python python-3.x asynchronous tornado


【解决方案1】:

除了按照 dano 的建议使用 tornado.process.Subprocess 之外,您还应该使用 stdout=tornado.process.Subprocess.STREAM 而不是 PIPE,并从 stdout/stderr 异步读取。使用PIPE 将适用于少量输出,但如果您使用PIPE 并且子进程尝试写入太多数据(过去是4KB,但在大多数现代Linux 系统中限制更高),您将在wait_for_exit() 中死锁)。

process = Subprocess([command], 
    stdout=Subprocess.STREAM, stderr=Subprocess.STREAM,
    shell=True)
out, err = yield [process.stdout.read_until_close(),
    process.stderr.read_until_close()]

【讨论】:

  • 在这种情况下,如果非零,获取返回码并引发异常的惯用方法是什么?谢谢 -
  • yield process.wait_for_exit(): tornadoweb.org/en/stable/…
【解决方案2】:

您需要在subprocess.Popen 周围使用tornado 的包装器以避免阻塞事件循环:

from tornado.process import Subprocess
from subprocess import PIPE
from tornado import gen

@gen.coroutine
def run_command(command):
    process = Subprocess([command], stdout=PIPE, stderr=PIPE, shell=True)
    yield process.wait_for_exit()  # This waits without blocking the event loop.
    out, err = process.stdout.read(), process.stderr.read()
    # Do whatever you do with out and err

【讨论】:

  • 这真的帮了我大忙!非常感谢!! :-)
  • 考虑wait_for_exit(raise_error=False),否则子进程返回非0会引发异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多