龙卷风网络报废比线程impl慢

时间:2018-05-12 15:42:37

标签: python tornado nonblocking

我使用龙卷风实现了一个简单的网页报废,主要的想法是将所有网址插入到队列q并生成多个工作人员,ping网址并检查它的状态(大多数网址不存在,即获得超时)

所有响应都插入到另一个队列q2但是它无关紧要因为在完成所有工作之后处理此队列

我还使用线程实现了相同的方法,与concurrency的编号相同,并且线程实现速度要快得多,尽管在等待来自Web的响应时踏板处于空闲状态,而龙卷风IOLoop应该是这种类型的最佳选择行为

我错过了什么? thx in advanced

from tornado import httpclient, gen, ioloop, queues

concurrency = 100

@gen.coroutine
def get_response(url):
    response = yield httpclient.AsyncHTTPClient().fetch(url, raise_error=False)
    return response


@gen.coroutine
def main():
    q = queues.Queue()
    q2 = queues.Queue()

    @gen.coroutine
    def fetch_url():
        url = yield q.get()
        try:
            response = yield get_response(url)
            q2.put((url, response.code))
        finally:
            q.task_done()

    @gen.coroutine
    def worker():
        while True:
            yield fetch_url()

    for url in urls:
        q.put(url)

    print("all tasks were sent...")

    # Start workers, then wait for the work queue to be empty.
    for _ in range(concurrency):
        worker()

    print("workers spwaned")

    yield q.join()

    print("done")


if __name__ == '__main__':
    io_loop = ioloop.IOLoop.current()
    io_loop.run_sync(main)

线程impl很简单(没有多处理)并使用以下代码

for i in range(concurrency):
  t = threading.Thread(target=worker, args=())
  t.setDaemon(True)
  t.start()

1 个答案:

答案 0 :(得分:0)

为什么这可能会变慢,原因有几个:

  1. 异步编程的目标不是速度,它是可伸缩性。异步实现应该在高并发性水平下表现更好(特别是,它将使用更少的内存),但在低并发级别可能没有差异或线程可能更快。

  2. Tornado的默认HTTP客户端是用纯python编写的,缺少一些对性能很重要的功能。特别是它无法重用连接。如果HTTP客户端请求的性能对您很重要,请改为使用基于libcurl的客户端:

    tornado.httpclient.AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient')
    
  3. 有时即使在异步HTTP客户端中DNS解析也会阻塞,这会限制有效的并发性。在Tornado 5.0之前,Tornado的默认HTTP客户端就是如此。对于基于curl的客户端,它取决于libcurl的构建方式。您需要使用c-ares库构建的libcurl版本。上次我看起来这在大多数Linux发行版上都没有默认完成。