3

私は竜巻に非常に慣れていません。Tornado でブロックするリクエストを処理する方法を見ていました。ブロッキング コードを別のスレッドで実行します。ただし、スレッド化された関数が終了するまで、メインスレッドは引き続きブロックされます。ここでは gen.coroutine を使用していませんが、試してみましたが、結果は同じです

counter = 0

def run_async(func):
    @wraps(func)
    def function_in_a_thread(*args, **kwargs):
        func_t = Thread(target=func, args=args, kwargs=kwargs)
        func_t.start()
    return function_in_a_thread

def long_blocking_function(index, sleep_time, callback):
    print "Entering run counter:%s" % (index,)
    time.sleep(sleep_time)
    print "Exiting run counter:%s" % (index,)

    callback('keyy' + index)


class FooHandler(tornado.web.RequestHandler):

    @web.asynchronous
    def get(self):

        global counter
        counter += 1
        current_counter = str(counter)

        print "ABOUT to spawn thread for counter:%s" % (current_counter,)
        long_blocking_function(
            index=current_counter,
            sleep_time=5, callback=self.done_waiting)


        print "DONE with the long function"

    def done_waiting(self, response):
        self.write("Whatever %s " % (response,))
        self.finish()


class Application(tornado.web.Application):
    def __init__(self):
        handlers = [(r"/foo", FooHandler),
                    ]

        settings = dict(
            debug=True,
        )

        tornado.web.Application.__init__(self, handlers, **settings)


def main():
    application = Application()
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()

リクエストを連続して発行すると、FooHandler がブロックされ、long_blocking_function が終了するまでリクエストを受け取りません。だから私は次のようなものを見ることになります

ABOUT to spawn thread for counter:1
Entering run counter:1
Exiting run counter:1
DONE with the long function
ABOUT to spawn thread for counter:2
Entering run counter:2
Exiting run counter:2
DONE with the long function
ABOUT to spawn thread for counter:3
Entering run counter:3
Exiting run counter:3
DONE with the long function

これらの行に沿って何かを期待していましたが (long_blocking_function への最初の呼び出しが終了する前に複数の要求を発行しているため)、上記のようなトレースしか表示されません

ABOUT to spawn thread for counter:1
DONE with the long function
ABOUT to spawn thread for counter:2
DONE with the long function
ABOUT to spawn thread for counter:3
DONE with the long function
ABOUT to spawn thread for counter:4
DONE with the long function

Tornado が非同期リクエストをブロックするのを見て、両方のソリューションを試しました。しかし、同じハンドラーへの連続した要求でそれらを実行すると、両方ともブロックされます。誰かが私が間違っていることを理解できますか? トルネードがマルチスレッドでうまくいかないことは知っていますが、ブロックしない方法で新しいスレッドを実行できるはずです。

4

3 に答える 3

1

タスクを別のスレッドにオフロードするときは、タスクが終了したときに呼び出されるイベント ループにコールバックを登録します。答えはこのスレッドにあります: How to make a library asynchronous in python

よろしくm。

于 2013-10-14T14:11:21.633 に答える
0

run_async定義したデコレータを実際に使用するのを忘れただけです。

import tornado.web
import functools
import threading
import time

counter = 0
def run_async(func):
    @functools.wraps(func)
    def function_in_a_thread(*args, **kwargs):
        func_t = threading.Thread(target=func, args=args, kwargs=kwargs)
        func_t.start()
    return function_in_a_thread


@run_async
def long_blocking_function(index, sleep_time, callback):
    print ("Entering run counter:%s" % (index,))
    time.sleep(sleep_time)
    print ("Exiting run counter:%s" % (index,))
    callback('keyy' + index)

class FooHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        global counter
        counter += 1
        current_counter = str(counter)

        print ("ABOUT to spawn thread for counter:%s" % (current_counter,))
        long_blocking_function(
            index=current_counter,
            sleep_time=5, callback=self.done_waiting)
        print ("DONE with the long function")

    def done_waiting(self, response):
        self.write("Whatever %s " % (response,))
        self.finish()


class Application(tornado.web.Application):
    def __init__(self):
        handlers = [(r"/foo", FooHandler),
                    ]

        settings = dict(
            debug=True,
        )

        tornado.web.Application.__init__(self, handlers, **settings)


def main():
    application = Application()
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()
于 2013-10-11T23:06:27.173 に答える