【发布时间】:2017-05-03 07:19:09
【问题描述】:
我正在尝试编写一个 Tornado 网络应用程序,它以协程的形式异步运行本地命令。这是精简的示例代码:
#! /usr/bin/env python3
import shlex
import asyncio
import logging
from tornado.web import Application, url, RequestHandler
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
logging.getLogger('asyncio').setLevel(logging.DEBUG)
async def run():
command = "python3 /path/to/my/script.py"
logging.debug('Calling command: {}'.format(command))
process = asyncio.create_subprocess_exec(
*shlex.split(command),
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT
)
logging.debug(' - process created')
result = await process
stdout, stderr = result.communicate()
output = stdout.decode()
return output
def run_sync(self, path):
command = "python3 /path/to/my/script.py"
logging.debug('Calling command: {}'.format(command))
try:
result = subprocess.run(
*shlex.split(command),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=True
)
except subprocess.CalledProcessError as ex:
raise RunnerError(ex.output)
else:
return result.stdout
class TestRunner(RequestHandler):
async def get(self):
result = await run()
self.write(result)
url_list = [
url(r"/test", TestRunner),
]
HTTPServer(Application(url_list, debug=True)).listen(8080)
logging.debug("Tornado server started at port {}.".format(8080))
IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')
IOLoop.instance().start()
当直接调用/path/to/my/script.py 时,它会按预期执行。此外,当我将TestHandler.get 实现为常规的同步方法(请参阅run_sync)时,它会正确执行。但是,当运行上述应用并调用/test时,日志显示:
DEBUG:asyncio:Using selector: EpollSelector
DEBUG:asyncio:execute program 'python3' stdout=stderr=<pipe>
DEBUG:asyncio:process 'python3' created: pid 21835
但是,ps 显示进程挂起:
$ ps -ef | grep 21835
berislav 21835 21834 0 19:19 pts/2 00:00:00 [python3] <defunct>
我感觉我没有实现正确的循环,或者我做错了,但是我看到的所有examples 都展示了如何使用asyncio.get_event_loop().run_until_complete(your_coro()),我找不到太多关于结合 asyncio 和 Tornado。欢迎所有建议!
【问题讨论】:
标签: python python-3.x tornado python-3.5 python-asyncio