[英]Python asyncio with Slack bot
我正在嘗試使用asyncio制作一個簡單的Slack機器人,主要使用此處的示例用於asyncio部分, 此處用於Slack機器人部分。
這兩個例子都是自己工作的,但是當我把它們放在一起時,似乎我的循環沒有循環:它經過一次然后死掉。 如果info
是一個長度等於1的列表,當在其中包含機器人的聊天室中鍵入消息時,會發生協程,但它永遠不會被觸發。 (所有協同程序現在都在嘗試打印消息,如果消息包含“/ time”,它會讓機器人在其詢問的聊天室中打印時間)。 鍵盤中斷也不起作用,我每次都要關閉命令提示符。
這是我的代碼:
import asyncio
from slackclient import SlackClient
import time, datetime as dt
token = "MY TOKEN"
sc = SlackClient(token)
@asyncio.coroutine
def read_text(info):
if 'text' in info[0]:
print(info[0]['text'])
if r'/time' in info[0]['text']:
print(info)
resp = 'The time is ' + dt.datetime.strftime(dt.datetime.now(),'%H:%M:%S')
print(resp)
chan = info[0]['channel']
sc.rtm_send_message(chan, resp)
loop = asyncio.get_event_loop()
try:
sc.rtm_connect()
info = sc.rtm_read()
if len(info) == 1:
asyncio.async(read_text(info))
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
我認為這是循環部分被打破,因為它似乎永遠不會到達協程。 所以也許一個更簡單的問這個問題的方法是什么是我的try:語句阻止它像我在后面的asyncio示例中循環? sc.rtm_connect()
有什么不喜歡的嗎?
我是asyncio的新手,所以我可能做了一些愚蠢的事情。 這是嘗試和解決這個問題的最好方法嗎? 最終我希望機器人做一些需要花費很長時間才能完成計算的東西,並且我希望它在那個時候保持響應,所以我認為我需要使用asyncio或某種程度的線程,但我願意更好的建議。
非常感謝,Alex
我將其更改為以下內容並且有效:
import asyncio
from slackclient import SlackClient
import time, datetime as dt
token = "MY TOKEN"
sc = SlackClient(token)
@asyncio.coroutine
def listen():
yield from asyncio.sleep(1)
x = sc.rtm_connect()
info = sc.rtm_read()
if len(info) == 1:
if 'text' in info[0]:
print(info[0]['text'])
if r'/time' in info[0]['text']:
print(info)
resp = 'The time is ' + dt.datetime.strftime(dt.datetime.now(),'%H:%M:%S')
print(resp)
chan = info[0]['channel']
sc.rtm_send_message(chan, resp)
asyncio.async(listen())
loop = asyncio.get_event_loop()
try:
asyncio.async(listen())
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
不完全確定為什么要修復它,但我改變的關鍵事情是將sc.rtm_connect()
調用放在協程中並使其成為x = sc.rtm_connect()
。 我也在最后調用了listen()
函數,這似乎是讓它永遠循環的原因,因為如果我把它拿出來,機器人不響應。 我不知道這是不是應該設置這種東西的方式,但它似乎在處理早期命令時繼續接受命令,我的松弛聊天看起來像這樣:
me [12:21 AM]
/time
[12:21]
/time
[12:21]
/time
[12:21]
/time
testbotBOT [12:21 AM]
The time is 00:21:11
[12:21]
The time is 00:21:14
[12:21]
The time is 00:21:16
[12:21]
The time is 00:21:19
請注意,它不會錯過任何我/time
請求,如果它不是異步執行此操作,它會發生這種情況。 此外,如果有人試圖復制這個,你會注意到如果你鍵入“/”,松弛會打開內置命令菜單。 我通過在前面鍵入一個空格來解決這個問題。
感謝您的幫助,如果您知道更好的方法,請告訴我。 它似乎不是一個非常優雅的解決方案,並且我使用cntrl-c鍵盤中斷結束后無法重啟機器人 - 它說
Task exception was never retrieved
future: <Task finished coro=<listen() done, defined at asynctest3.py:8> exception=AttributeError("'NoneType' object has no attribute 'recv'",)>
Traceback (most recent call last):
File "C:\Users\Dell-F5\AppData\Local\Programs\Python\Python35-32\Lib\asyncio\tasks.py", line 239, in _step
result = coro.send(None)
File "asynctest3.py", line 13, in listen
info = sc.rtm_read()
File "C:\Users\Dell-F5\Envs\sbot\lib\site-packages\slackclient\_client.py", line 39, in rtm_read
json_data = self.server.websocket_safe_read()
File "C:\Users\Dell-F5\Envs\sbot\lib\site-packages\slackclient\_server.py", line 110, in websocket_safe_read
data += "{0}\n".format(self.websocket.recv())
AttributeError: 'NoneType' object has no attribute 'recv'
我猜這意味着它沒有很好地關閉websockets。 無論如何,這只是一個煩惱,至少主要問題是固定的。
亞歷克斯
在協程內部進行阻塞IO調用會破壞使用asyncio的目的(例如, info = sc.rtm_read()
)。 如果您沒有選擇,請使用loop.run_in_executor在其他線程中運行阻塞調用。 但是要小心,可能需要一些額外的鎖定。
但是,似乎有一些基於asyncio的松弛客戶端庫可以使用:
編輯: Butterfield使用Slack實時消息傳遞API。 它甚至提供了一個echo bot示例 ,看起來非常像您要實現的目標:
import asyncio
from butterfield import Bot
@asyncio.coroutine
def echo(bot, message):
yield from bot.post(
message['channel'],
message['text']
)
bot = Bot('slack-bot-key')
bot.listen(echo)
butterfield.run(bot)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.