[英]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.