tornado 实现 将阻塞函数 改变为非阻塞 助力并发开发(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yangxiaodong88/article/details/82022309

背景

上次类似的文章,只是展示了将阻塞函数变为了非阻塞。 今天又有一些领悟。 @run_on_executor 装饰器的作用, 不管是变为非阻塞还可以 像celery 一个执行异步任务。

1、 将阻塞函数转非阻塞 函数 并获取到值



from tornado.concurrent import run_on_executor
import time
import tornado.web
import tornado.gen
from concurrent.futures import ThreadPoolExecutor
from concurrent import futures
import asyncio


class LogicAsyTest():
    # executor = ThreadPoolExecutor(1)
    # executor = ThreadPoolExecutor(255)
    # executor = ThreadPoolExecutor(200)
    # executor = ThreadPoolExecutor(100)
    executor = ThreadPoolExecutor()

    def __init__(self):
        pass

    @tornado.gen.coroutine
    def bb(self):
        res = yield self.my_sleep()
        return res

    async def execute(self, base_url):
        """ 这个方法是非常好的的"""
        result = Result.result_success()

        res = await self.bb()  # 这个是正确的
        result['content'] = res

        # time.sleep(100)
        OHHOLog.print_log("test result")
        OHHOLog.print_log(result)
        return result

    async def async_execute(self, base_url):
        result = await self.execute(base_url)
        return result

    @run_on_executor
    def my_sleep(self):
        # data = dict()
        # data["name"] = "哈哈"
        # success = self.introduce.add(data)
        # return success
        time.sleep(5)
        return 5

在这个示例中, 将sleep 函数转为非阻塞的并且要回去到返回值

执行的结果现象就是整个协程的接口 会花费5秒, 5秒阻塞当前的协程的执行。

2、将阻塞函数变为非阻塞函数, 相当于异步 线程跑在后台。 就像celery 一样


from tornado.concurrent import run_on_executor
import time
import tornado.web
import tornado.gen

from concurrent.futures import ThreadPoolExecutor
from concurrent import futures

import asyncio


class LogicAsyTest4():
    # executor = ThreadPoolExecutor(1)
    # executor = ThreadPoolExecutor(255)
    # executor = ThreadPoolExecutor(200)
    # executor = ThreadPoolExecutor(100)
    executor = ThreadPoolExecutor()

    def __init__(self):
        pass

    @tornado.gen.coroutine
    def bb(self):
        res = yield self.my_sleep()
        return res

    async def execute(self, base_url):
        """ 这个方法是非常好的的"""
        result = Result.result_success()


        self.my_sleep()

        OHHOLog.print_log("test result")
        OHHOLog.print_log(result)
        return result

    async def async_execute(self, base_url):
        result = await self.execute(base_url)
        return result

    @run_on_executor
    def my_sleep(self):
        time.sleep(5)
        OHHOLog.print_log("哈哈哈 mysleep")
        return 5

运行结果现象是, 接口立马返回。后台新另起的线程会去跑my_sleep的程序。 不影响接口的向下执行和返回。 当不需要返回值的程序中就会执行这样的程序。调用方式

self.my_sleep() 

不需要yied 获取值。 这样也是非阻塞, 释放了GIL

使用await 和不使用await 之间区别



from tornado.concurrent import run_on_executor
import time
import tornado.web
import tornado.gen

from concurrent.futures import ThreadPoolExecutor
from concurrent import futures

import asyncio


class LogicAsyTest4():
    # executor = ThreadPoolExecutor(1)
    # executor = ThreadPoolExecutor(255)
    # executor = ThreadPoolExecutor(200)
    # executor = ThreadPoolExecutor(100)
    executor = ThreadPoolExecutor()

    def __init__(self):
       pass

    @tornado.gen.coroutine
    def bb(self):
        res = yield self.my_sleep()
        return res

    # @tornado.gen.coroutine
    # def bb(self):
    #     yield self.my_sleep()


    async def execute(self, base_url):
        """ 这个方法是非常好的的"""
        result = Result.result_success()

        # res = await self.bb()  # 这个是正确的
        # self.my_sleep()
        # await self.bb() # 实验数据证明 这是使用await 需要获取到结果 就会阻塞当前的协程, 但不会阻塞主线程
        self.bb()  # 不需要await 获取结果 就不会阻塞当前协程 也就跟不会阻塞当前主线程不会影响 别的协程执行
        # result['content'] = res
        # time.sleep(5)
        OHHOLog.print_log("test result")
        OHHOLog.print_log(result)
        return result

    async def async_execute(self, base_url):
        result = await self.execute(base_url)
        return result

    @run_on_executor
    def my_sleep(self):
        time.sleep(5)
        OHHOLog.print_log("哈哈哈 mysleep")
        return 5

对于 不需要返回值 类似于celery 的异步方法就不需要yield from 或者 await 驱动的 后面也咩有必要中间再加入一个方法。 不需要获取返回值直接调用 @run_on_executor 方法就可以了。不需要重建的协程。 像这种情况 通过测试 当需要返回着的时候 使用await 驱动协程获取返回值, 这个时候会阻塞当前的协程但是不会阻塞当前的主线程。 不用await 的话也就是不驱动拿到具体的值就直接像调用正常方法一样调用, 中间不要用协程(没有用, 还增加代码的执行之间)。

猜你喜欢

转载自blog.csdn.net/yangxiaodong88/article/details/82022309
今日推荐