系统规格 -MacOS 10.13.6 -Python 3.7.0 -龙卷风5.1.1
我想使用ThreadPoolExecutor运行阻止功能 在提供RESTful服务的Tornado实例中。
只要我不试图产生执行函数返回的结果,ThreadPool就可以按预期工作并并行产生四个工作线程(请参见下面的代码和控制台日志)。
ThreadPoolExecutor没有产生结果
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.4
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
menuBar: MenuBar {
Menu {
title: qsTr("&File")
Action { text: qsTr("&New...") }
Action { text: qsTr("&Open...") }
Action { text: qsTr("&Save") }
Action { text: qsTr("Save &As...") }
MenuSeparator { }
Action { text: qsTr("&Quit") }
}
Menu {
title: qsTr("&Edit")
Action { text: qsTr("Cu&t") }
Action { text: qsTr("&Copy") }
Action { text: qsTr("&Paste") }
}
Menu {
title: qsTr("&Help")
Action { text: qsTr("&About") }
}
}
}
控制台输出
import time
import tornado.web
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor
from tornado.ioloop import IOLoop
MAX_WORKERS = 4
i = 0
class Handler(tornado.web.RequestHandler):
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
@run_on_executor
def background_task(self, i):
print("going sleep %s" % (i))
time.sleep(10);
print("waking up from sleep %s" % (i))
return str(i)
@tornado.gen.coroutine
def get(self):
global i
i+=1
self.background_task(i)
def make_app():
return tornado.web.Application([
(r"/", Handler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8000, '0.0.0.0')
IOLoop.current().start()
可以看出,有四个并行的工作程序正在运行,并且一旦完成,就会执行一个排队的函数。
但是,当我尝试使用协程产生返回函数时,我遇到了一些问题。虽然它不能完全阻止IoLoop,但会延迟而没有清晰的模式。
更改后的代码:ThreadPoolExecutor现在产生结果
going sleep 1
going sleep 2
going sleep 3
going sleep 4
waking up from sleep 1
going sleep 5
waking up from sleep 2
going sleep 6
waking up from sleep 3
going sleep 7
waking up from sleep 4
going sleep 8
waking up from sleep 5
going sleep 9
waking up from sleep 6
waking up from sleep 7
waking up from sleep 8
waking up from sleep 9
查看控制台输出,只有一个线程运行第一个和第二个请求,并在单个线程完成后执行排队任务(延迟10秒启动任务2,另一个延迟启动任务3)。但是,任务3、4、5和6并行执行,但每个调用之间的延迟有所不同。
控制台输出
MAX_WORKERS = 4
i = 0
class Handler(tornado.web.RequestHandler):
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
@run_on_executor
def background_task(self, i):
print("%s: Going sleep %s" % (time.time(), i))
time.sleep(10);
print("%s: Waiking up from sleep %s" % (time.time(), i))
return str(i)
@tornado.gen.coroutine
def get(self):
global i
i+=1
result = yield self.background_task(i)
self.write(result)
有人可以解释这种行为吗?你有什么解决办法吗?