Skip to content

解决回调函数只能传一个值的问题

解决方案就是使用改造回调函数为闭包函数,原理就是调用闭包函数时,没有参数限制,这个时候我们可以任意传递参数。

然后该闭包返回的是真正的回调函数callback,这个callback中我们只写一个形参就完了。

python
# -*- coding = utf-8 -*-
import os
import asyncio
import aiohttp
from threading import Thread

policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
semaphore = asyncio.Semaphore(os.cpu_count())

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}


def content_type_map(content_type, response):
    ctm = {
        "application/json": response.json,
        "text/html": response.text,
    }
    return ctm[content_type]() if content_type in ctm else response.read()


async def get_request(url):
    """ 基于aiohttp实现的异步协程对象(一组操作集) """
    async with semaphore:
        async with aiohttp.ClientSession(trust_env=True) as session:
            async with await session.request(method='get', url=url, headers=headers) as response:
                result = await content_type_map(response.headers.get('content-type'), response)
                return result


def task_callback(cb):
    """
    任务对象的回调函数,该回调函数有且只有一个参数
    :param cb: 该回调函数的调用者,即任务对象
    :return:
    """
    print('回调函数执行成功', type(cb.result()), cb.result())


def task_callback2(x1, x2, x3):
    """
    任务对象的回调闭包函数,原理就是调用闭包函数时,没有参数限制,
    然后该闭包返回的是真正的回调函数callback,这个callback中我们只写一个形参就完了
    """

    def callback(cb):
        print('回调函数执行成功', x1, x2, x3, cb.result())

    return callback


def event_loop_server_forever(loop):
    """ 事件循环服务器的永久运行事件 """
    asyncio.set_event_loop(loop)
    loop.run_forever()


async def work():
    new_loop = asyncio.new_event_loop()
    t = Thread(target=event_loop_server_forever, args=(new_loop,))
    t.start()
    for i in range(5):
        url = f'http://httpbin.org/get?id={i}'
        future = asyncio.run_coroutine_threadsafe(get_request(url), new_loop)
        # future.add_done_callback(task_callback)  # 默认的回调只能有一个参数
        # 如果有需要在回调中额外的传递参数,可以将回调函数写成闭包的形式,能额外传递任意参数
        future.add_done_callback(task_callback2('x1', 'x2', 'x3'))
    print('主线程继续执行')
    t.join()


if __name__ == '__main__':
    asyncio.run(work())