使 Python 松弛机器人异步
Making a Python slack bot asynchronous
我一直在尝试在 Slack 中制作一个机器人,即使它没有完成对早期命令的处理也能保持响应,这样它就可以去做一些需要一些时间的事情而不会锁定。它应该return先完成的。
我想我已经完成了一部分:它现在不会忽略在较早的命令完成之前输入的内容 运行。但它仍然不允许线程彼此 "overtake" - 一个被称为 first 的命令将首先 return,即使它需要更长的时间才能完成。
import asyncio
from slackclient import SlackClient
import time, datetime as dt
token = "my token"
sc = SlackClient(token)
@asyncio.coroutine
def sayHello(waitPeriod = 5):
yield from asyncio.sleep(waitPeriod)
msg = 'Hello! I waited {} seconds.'.format(waitPeriod)
return msg
@asyncio.coroutine
def listen():
yield from asyncio.sleep(1)
x = sc.rtm_connect()
info = sc.rtm_read()
if len(info) == 1:
if r'/hello' in info[0]['text']:
print(info)
try:
waitPeriod = int(info[0]['text'][6:])
except:
print('Can not read a time period. Using 5 seconds.')
waitPeriod = 5
msg = yield from sayHello(waitPeriod = waitPeriod)
print(msg)
chan = info[0]['channel']
sc.rtm_send_message(chan, msg)
asyncio.async(listen())
def main():
print('here we go')
loop = asyncio.get_event_loop()
asyncio.async(listen())
loop.run_forever()
if __name__ == '__main__':
main()
当我在 Slack 聊天 window 中键入 /hello 12
和 /hello 2
时,机器人现在会响应这两个命令。但是,在完成 /hello 12
命令之前,它不会处理 /hello 2
命令。我对 asyncio 的理解还在进行中,所以我很可能犯了一个非常基本的错误。我在 中被告知 sc.rtm_read()
之类的东西是阻塞函数。这是我问题的根源吗?
非常感谢,
亚历克斯
发生的事情是您的 listen()
协程在 yield from sayHello()
语句处阻塞。只有 sayHello()
完成后,listen()
才能继续其愉快的旅程。症结在于 yield from
语句(或 Python 3.5+ 中的 await
)正在阻塞。它将两个协程链接在一起,并且 'parent' 协程在链接的 'child' 协程完成之前无法完成。 (但是,'neighbouring' 不属于同一链接链的协程可以同时自由进行。
在这种情况下释放 sayHello()
而不阻止 listen()
的简单方法是使用 listen()
作为专用的侦听协程并将所有后续操作卸载到它们自己的 Task
包装器,因此不会妨碍 listen()
响应后续传入的消息。沿着这些路线。
@asyncio.coroutine
def sayHello(waitPeriod, sc, chan):
yield from asyncio.sleep(waitPeriod)
msg = 'Hello! I waited {} seconds.'.format(waitPeriod)
print(msg)
sc.rtm_send_message(chan, msg)
@asyncio.coroutine
def listen():
# connect once only if possible:
x = sc.rtm_connect()
# use a While True block instead of repeatedly calling a new Task at the end
while True:
yield from asyncio.sleep(0) # use 0 unless you need to wait a full second?
#x = sc.rtm_connect() # probably not necessary to reconnect each loop?
info = sc.rtm_read()
if len(info) == 1:
if r'/hello' in info[0]['text']:
print(info)
try:
waitPeriod = int(info[0]['text'][6:])
except:
print('Can not read a time period. Using 5 seconds.')
waitPeriod = 5
chan = info[0]['channel']
asyncio.async(sayHello(waitPeriod, sc, chan))
我一直在尝试在 Slack 中制作一个机器人,即使它没有完成对早期命令的处理也能保持响应,这样它就可以去做一些需要一些时间的事情而不会锁定。它应该return先完成的。
我想我已经完成了一部分:它现在不会忽略在较早的命令完成之前输入的内容 运行。但它仍然不允许线程彼此 "overtake" - 一个被称为 first 的命令将首先 return,即使它需要更长的时间才能完成。
import asyncio
from slackclient import SlackClient
import time, datetime as dt
token = "my token"
sc = SlackClient(token)
@asyncio.coroutine
def sayHello(waitPeriod = 5):
yield from asyncio.sleep(waitPeriod)
msg = 'Hello! I waited {} seconds.'.format(waitPeriod)
return msg
@asyncio.coroutine
def listen():
yield from asyncio.sleep(1)
x = sc.rtm_connect()
info = sc.rtm_read()
if len(info) == 1:
if r'/hello' in info[0]['text']:
print(info)
try:
waitPeriod = int(info[0]['text'][6:])
except:
print('Can not read a time period. Using 5 seconds.')
waitPeriod = 5
msg = yield from sayHello(waitPeriod = waitPeriod)
print(msg)
chan = info[0]['channel']
sc.rtm_send_message(chan, msg)
asyncio.async(listen())
def main():
print('here we go')
loop = asyncio.get_event_loop()
asyncio.async(listen())
loop.run_forever()
if __name__ == '__main__':
main()
当我在 Slack 聊天 window 中键入 /hello 12
和 /hello 2
时,机器人现在会响应这两个命令。但是,在完成 /hello 12
命令之前,它不会处理 /hello 2
命令。我对 asyncio 的理解还在进行中,所以我很可能犯了一个非常基本的错误。我在 sc.rtm_read()
之类的东西是阻塞函数。这是我问题的根源吗?
非常感谢, 亚历克斯
发生的事情是您的 listen()
协程在 yield from sayHello()
语句处阻塞。只有 sayHello()
完成后,listen()
才能继续其愉快的旅程。症结在于 yield from
语句(或 Python 3.5+ 中的 await
)正在阻塞。它将两个协程链接在一起,并且 'parent' 协程在链接的 'child' 协程完成之前无法完成。 (但是,'neighbouring' 不属于同一链接链的协程可以同时自由进行。
在这种情况下释放 sayHello()
而不阻止 listen()
的简单方法是使用 listen()
作为专用的侦听协程并将所有后续操作卸载到它们自己的 Task
包装器,因此不会妨碍 listen()
响应后续传入的消息。沿着这些路线。
@asyncio.coroutine
def sayHello(waitPeriod, sc, chan):
yield from asyncio.sleep(waitPeriod)
msg = 'Hello! I waited {} seconds.'.format(waitPeriod)
print(msg)
sc.rtm_send_message(chan, msg)
@asyncio.coroutine
def listen():
# connect once only if possible:
x = sc.rtm_connect()
# use a While True block instead of repeatedly calling a new Task at the end
while True:
yield from asyncio.sleep(0) # use 0 unless you need to wait a full second?
#x = sc.rtm_connect() # probably not necessary to reconnect each loop?
info = sc.rtm_read()
if len(info) == 1:
if r'/hello' in info[0]['text']:
print(info)
try:
waitPeriod = int(info[0]['text'][6:])
except:
print('Can not read a time period. Using 5 seconds.')
waitPeriod = 5
chan = info[0]['channel']
asyncio.async(sayHello(waitPeriod, sc, chan))