繁体   English   中英

Python Asyncio run_forever()和任务

[英]Python Asyncio run_forever() and Tasks

我修改了此代码以在异步Python中使用Google Cloud PubSub: https//github.com/cloudfind/google-pubsub-asyncio

import asyncio
import datetime
import functools
import os

from google.cloud import pubsub
from google.gax.errors import RetryError
from grpc import StatusCode

async def message_producer():
    """ Publish messages which consist of the current datetime """
    while True:
        await asyncio.sleep(0.1)


async def proc_message(message):
    await asyncio.sleep(0.1)
    print(message)
    message.ack()


def main():
    """ Main program """
    loop = asyncio.get_event_loop()

    topic = "projects/{project_id}/topics/{topic}".format(
        project_id=PROJECT, topic=TOPIC)
    subscription_name = "projects/{project_id}/subscriptions/{subscription}".format(
        project_id=PROJECT, subscription=SUBSCRIPTION)

    subscription = make_subscription(
        topic, subscription_name)

    def create_proc_message_task(message):
        """ Callback handler for the subscription; schedule a task on the event loop """
        print("Task created!")
        task = loop.create_task(proc_message(message))

    subscription.open(create_proc_message_task)
    # Produce some messages to consume

    loop.create_task(message_producer())

    print("Subscribed, let's do this!")
    loop.run_forever()


def make_subscription(topic, subscription_name):
    """ Make a publisher and subscriber client, and create the necessary resources """
    subscriber = pubsub.SubscriberClient()
    try:
        subscriber.create_subscription(subscription_name, topic)
    except:
        pass
    subscription = subscriber.subscribe(subscription_name)

    return subscription


if __name__ == "__main__":
    main()

我基本上删除了发布代码,仅使用订阅代码。 但是,最初我没有包括loop.create_task(message_producer())行。 我认为任务是按照预期的方式创建的,但实际上它们从未真正运行过。 仅当我添加上述行后,代码才能正确执行并且所有创建的任务都将运行。 是什么导致这种行为?

PubSub正在从另一个线程调用create_proc_message_task回调。 由于create_task 不是线程安全的 ,因此只能从运行事件循环的线程(通常是主线程)中调用它。 若要更正此问题,请将loop.create_task(proc_message(message))替换为asyncio.run_coroutine_threadsafe(proc_message(message), loop)message_producer

至于为什么message_producer似乎可以修复代码,请考虑与create_task相比, run_coroutine_threadsafe两件事:

  • 它以线程安全的方式运行,因此并发执行时事件循环数据结构不会损坏。
  • 它确保事件循环以最快的机会唤醒,以便它可以处理新任务。

在您的情况下, create_task将任务添加到了循环的可运行队列中(没有任何锁定),但是无法确保唤醒,因为在事件循环线程中运行时不需要这样做。 然后, message_producer用来强制循环以规则的时间间隔唤醒,这是它还检查并执行可运行任务的时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM