簡體   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