2016-10-30 27 views
1

私は、以前のコマンドの処理が終了していなくても反応し続けるスラックでボットを作ろうとしていたので、ロックせずに何か時間がかかることがありました。それは最初に終わったものを返すべきです。Pythonスラックボットを非同期にする

私はそこに途中で入っていると思います。以前のコマンドが実行を終了する前に入力されたものを無視しないようになりました。しかし、それでもスレッドはお互いを「追い越す」ことはできません。完了までに時間がかかっても、最初に呼び出されたコマンドが最初に返されます。

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() 

私はスラックチャットウィンドウに/hello 12/hello 2を入力

、ボットは現在、両方のコマンドに応答しません。ただし、 /hello 12コマンドの実行が完了するまでは、 /hello 2コマンドは処理されません。 asyncioの理解は進んでいるので、私は非常に基本的なエラーを作り出している可能性があります。私は previous questionで、 sc.rtm_read()のようなものが機能をブロックしていると言われました。それは私の問題の根源ですか?

おかげで多くは、何が起こっている アレックス

+0

どのOSとどのバージョンのPython(2または3)ですか? –

+0

3.5、asyncioはPython 3.3以降でしか利用できないと思います。 –

答えて

1

は、あなたのlisten()コルーチンがyield from sayHello()の文でブロックされています。一度だけsayHello()が完了すると、listen()は快晴を続けることができます。要点は、yield fromの文(またはPython 3.5以降のawait)がブロックされていることです。それは2つのコルーチンを連鎖させ、リンクされた「子」コルーチンが完了するまで、「親」コルーチンは完了できません。 (しかし、同じ連鎖の一部ではない「隣接する」コルーチンは、その間に処理が自由です)。

この場合にはlisten()を保持せずにsayHello()を解放する簡単な方法は、専用のリスニングコルーチンとして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)) 
+1

素晴らしいです、それは動作します!どうもありがとう。ループの1秒間の睡眠についてのメモ、私はそこに[速度制限](https://api.slack.com/docs/rate-limits)の余裕があるためにそれを持っていました。これらの制限の一部として 'rtm_read()'を考慮するかどうかわかりません。私が睡眠をゼロに設定すると、それは機能し続けます、そして、それははるかに反応しますが、弛緩が口座を絞り終わらせるかどうか分かりません。私はそうでないと聞くまで私はゼロにしておきます。 –

関連する問題