問題描述
我有一個永遠(yuǎn)運行的腳本(它檢查文件的變化).每當(dāng)制作奇怪的文件時,我都需要發(fā)送 Discord 消息.
I have a script that is constantly running forever (it checks changes in files). I need to send Discord messages whenever a weird file is made.
- 問題是,事件監(jiān)聽函數(shù)(下面的
def run(self):
)來自一個子類,所以我不能把它改成async def run(self):代碼>.因此我不能使用
await channel.send()
- 我對此的解決方案是使用
run_coroutine_threadsafe
,如下所述:https://stackoverflow.com/一個/53726266/9283107.效果很好!但問題是,消息被放入隊列中,并且在此腳本完成之前它們永遠(yuǎn)不會被發(fā)送(在我的情況下是:永遠(yuǎn)不會).我假設(shè)發(fā)送消息函數(shù)被放入該腳本所在的線程中,因此線程永遠(yuǎn)不會到達(dá)它們?
- Problem is, the event watching function (
def run(self):
below) is from a subclass, so I can't change it toasync def run(self):
. Therefore I can't useawait channel.send()
- My solution to this was to use
run_coroutine_threadsafe
like explained here: https://stackoverflow.com/a/53726266/9283107. That works good! But the problem is, the messages get put into a queue and they never get sent until this script finishes (which in my case would be: never). I assume the send message functions get put into the thread that this script is on, therefore the thread never gets to them?
也許我們可以將 run_coroutine_threadsafe
扔到一個單獨的線程中或什么的?這是我能做的最小的例子,它仍然顯示了我的子類問題.
Maybe we can throw the run_coroutine_threadsafe
into a separate thread or something? This is the most minimal example I can make that still shows my subclass problem.
import discord
import os
import asyncio
import time
# CHANNEL_ID = 7659170174????????
client = discord.Client()
channel = None
class Example():
# Imagine this run comes from a subclass, so you can't add sync to it!
def run(self):
# await channel.send('Test') # We can't do this because of the above comment
asyncio.run_coroutine_threadsafe(channel.send('Test'), _loop)
print('Message sent')
@client.event
async def on_ready():
print('Discord ready')
global channel
channel = client.get_channel(CHANNEL_ID)
for i in range(2):
Example().run()
time.sleep(3)
print('Discord messages should appear by now. Sleeping for 20s to give it time (technically this would be infinite)')
time.sleep(20)
print('Script done. Now they only get sent for some reason')
_loop = asyncio.get_event_loop()
client.run('Your secret token')
推薦答案
首先,請注意,您不能從 async 調(diào)用阻塞代碼,例如
.要啟動一個阻塞函數(shù)并讓它與 asyncio 通信,您可以從 time.sleep()
定義on_ready
甚至從頂層生成一個后臺線程,如下所示:
First, note that you're not allowed to call blocking code such as time.sleep()
from an async def
. To start a blocking function and have it communicate with asyncio, you can spawn a background thread from on_ready
or even from top-level, like this:
# checker_function is the function that blocks and that
# will invoke Example.run() in a loop.
threading.Thread(
target=checker_function,
args=(asyncio.get_event_loop(), channel)
).start()
您的主線程將運行 asyncio 事件循環(huán),而您的后臺線程將檢查文件,使用 asyncio.run_coroutine_threadsafe()
與 asyncio 和 discord 進(jìn)行通信.
Your main thread will run the asyncio event loop and your background thread will check the files, using asyncio.run_coroutine_threadsafe()
to communicate with asyncio and discord.
正如您鏈接到的答案下的評論中指出的那樣,asyncio.run_coroutine_threadsafe
假定您有多個線程正在運行(因此是線程安全的"),其中一個運行事件循環(huán).在您實現(xiàn)之前,任何使用 asyncio.run_coroutine_threadsafe
的嘗試都會失敗.
As pointed out in a comment under the answer you linked to, asyncio.run_coroutine_threadsafe
assumes that you have multiple threads running (hence "thread-safe"), one of which runs the event loop. Until you implement that, any attempt to use asyncio.run_coroutine_threadsafe
will fail.
這篇關(guān)于在單獨的線程中執(zhí)行 run_coroutine_threadsafe的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!