龙卷风python的简单异步示例

use*_*407 8 python asynchronous tornado

我想找到简单的异步服务器示例.我有很多等待,数据库事务等功能:等等:

def blocking_task(n):
    for i in xrange(n):
        print i
        sleep(1)
    return i
Run Code Online (Sandbox Code Playgroud)

我需要在没有阻塞的情况下在分离的进程中运行它 可能吗?

dan*_*ano 16

Tornado旨在在单个线程中运行所有操作,但利用异步I/O来尽可能避免阻塞.如果您正在使用的数据库具有异步Python绑定(理想情况下适用于Tornado,例如适用于MongoDB的Motor或适用于Postgres的momoko),那么您将能够在不阻塞服务器的情况下运行数据库查询; 不需要单独的进程或线程.

为了解决您给出的确切示例,在哪里time.sleep(1)调用,您可以使用此方法通过龙卷风协同程序异步执行:

#!/usr/bin/python

import tornado.web
from tornado.ioloop import IOLoop
from tornado import gen 
import time

@gen.coroutine
def async_sleep(seconds):
    yield gen.Task(IOLoop.instance().add_timeout, time.time() + seconds)

class TestHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        for i in xrange(100):
            print i
            yield async_sleep(1)
        self.write(str(i))
        self.finish()


application = tornado.web.Application([
    (r"/test", TestHandler),
    ])  

application.listen(9999)
IOLoop.instance().start()
Run Code Online (Sandbox Code Playgroud)

有趣的是async_sleep.该方法正在创建一个异步Task,它正在调用该ioloop.add_timeout方法.add_timeout将在给定的秒数后运行指定的回调,而不会在等待超时到期时阻止ioloop.它期望两个论点:

add_timeout(deadline, callback) # deadline is the number of seconds to wait, callback is the method to call after deadline.
Run Code Online (Sandbox Code Playgroud)

正如您在上面的示例中所看到的,我们实际上只是add_timeout在代码中明确地提供了一个参数,这意味着我们最终会这样:

add_timeout(time.time() + seconds, ???)
Run Code Online (Sandbox Code Playgroud)

我们没有提供预期的回调参数.实际上,在gen.Task执行时add_timeout,它会callback在显式提供的参数的末尾附加关键字参数.所以这:

yield gen.Task(loop.add_timeout, time.time() + seconds)
Run Code Online (Sandbox Code Playgroud)

结果在gen.Task()中执行:

loop.add_timeout(time.time() + seconds, callback=gen.Callback(some_unique_key))
Run Code Online (Sandbox Code Playgroud)

gen.Callback超时后执行时,它表示gen.Task完成,程序执行将继续到下一行.这种流程很难完全理解,至少在开始时(当我第一次阅读它时,它肯定适合我).阅读Tornado gen模块文档几次可能会有所帮助.


Iar*_*lav 6

import tornado.web
from tornado.ioloop import IOLoop
from tornado import gen

from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor   # `pip install futures` for python2

MAX_WORKERS = 16

class TestHandler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)

    """
    In below function goes your time consuming task
    """

    @run_on_executor
    def background_task(self):
        sm = 0
        for i in range(10 ** 8):
            sm = sm + 1

        return sm

    @tornado.gen.coroutine
    def get(self):
        """ Request that asynchronously calls background task. """
        res = yield self.background_task()
        self.write(str(res))

class TestHandler2(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        self.write('Response from server')
        self.finish()


application = tornado.web.Application([
    (r"/A", TestHandler),
    (r"/B", TestHandler2),
    ])

application.listen(5000)
IOLoop.instance().start()
Run Code Online (Sandbox Code Playgroud)

当您运行上面的代码时,您可以在http://127.0.0.1:5000/A上运行计算成本高昂的操作,这不会阻止执行,请在访问后立即访问 http://127.0.0.1:5000/B http://127.0.0.1:5000/A.