<p>上面的要点是正确的,从技术上讲,对于多路复用I/O(如<code>select()</code>,<code>epoll()</code>)的阻塞调用以及BSD/iOS、Windows变体,您无法做到这一点。这些调用允许超时规范,因此您可以通过在短时间间隔内重复轮询,然后将工作从主线程传递给异步处理程序来接近。在这种情况下,读取是在主线程上完成的,多个读取可以表示它们准备好了,而主线程主要用于该任务。在</p>
<p>如果问题的规模是小到中,那么没有什么能比<code>epoll()...read()</code>甚至<code>select()...read()</code>强。如果您的问题(读取通道的数量)是在小方面。所以我建议你考虑一下——从主线程上尽可能多地处理请求。在</p>
<p>如果您正在寻找一个异步解决方案,那么您最好的选择之一是<code>grequests</code>库,以便于使用和提高性能。要获得一个想法,请运行以下客户机-服务器对。请注意,在这里使用tornado是无关的,而且只在服务器端,而您关心的是客户端。在</p>
<p>试试这个-性能的差别是白天和黑夜。在</p>
<p><strong>您的解决方案由客户端.py类,它使用<code>grequests</code>异步发出<code>get()</code>请求。在</p>
<p><strong>服务器.py</strong></p>
<pre><code>from tornado import (httpserver, options,
ioloop, web, gen)
import time
import ujson as json
from collections import defaultdict
class Check(web.RequestHandler):
@gen.coroutine
def get(self):
try:
data = int(self.get_argument('data'))
except ValueError:
raise web.HTTPError(400, reason='Invalid value for data')
delay = 100
start = time.time()
print('Processed: {!r}'.format(data))
yield gen.Task(ioloop.IOLoop.instance().add_timeout, start + delay / 1000.)
self.write('.')
end = time.time()
self.finish()
if __name__ == '__main__':
port = 4545
application = web.Application([
(r'/get', Check)
])
http_server = httpserver.HTTPServer(application)
http_server.listen(port)
print('Listening on port: {}'.format(port))
ioloop.IOLoop.instance().start()
</code></pre>
<p><strong>客户端.py</strong></p>
^{pr2}$
<p>这是一个真正的异步解决方案,或者说是在CPython/python中最接近的解决方案。没有使用轮询器。在</p>