2016-10-27 21 views
0

私はいくつかのシェルコマンドを実行する必要があるスクリプトを持っています。しかし、コマンドが完了するのに時間がかかり過ぎると、強制的に殺さなければなりません。次のコードスニペットを考えてみましょう:asyncioはタイムアウト時にサブプロセスを終了します

import asyncio, random 

q = asyncio.Queue() 

MAX_WAIT = 5 

@asyncio.coroutine 
def blocking_task(sec): 
    print('This task will sleep {} sec.'.format(sec)) 
    create = asyncio.create_subprocess_shell(
     'sleep {s}; echo "Woke up after {s} sec." >> ./tst.log'.format(s=sec), 
     stdout=asyncio.subprocess.PIPE) 
    proc = yield from create 
    yield from proc.wait() 

@asyncio.coroutine 
def produce(): 
    while True: 
     q.put_nowait(random.randint(3,8)) 
     yield from asyncio.sleep(0.5 + random.random()) 

@asyncio.coroutine 
def consume(): 
    while True: 
     value = yield from q.get() 
     try: 
      yield from asyncio.wait_for(blocking_task(value), MAX_WAIT) 
     except asyncio.TimeoutError: 
      print('~/~ Job has been cancelled !!') 
     else: 
      print('=/= Job has been done :]') 


loop = asyncio.get_event_loop() 
asyncio.ensure_future(produce()) 
asyncio.ensure_future(consume()) 
loop.run_forever() 

このコードは次のような出力を生成:

This task will sleep 4 sec. 
=/= Job has been done :] 
This task will sleep 8 sec. 
~/~ Job has been cancelled !! 
This task will sleep 5 sec. 
~/~ Job has been cancelled !! 

だから、彼らは仕上げに時間がかかりすぎる場合に予想される、ジョブが停止されているとして、それが働いているようです。

Woke up after 4 sec. 
Woke up after 8 sec. 
Woke up after 5 sec. 

私は他のプロセスがなければならないとして、ログに一つだけの行があるはず期待:私は、ログをチェックすると、私はしかし、時間のかかるタスクを実行し続け、実際に中止された/殺した/停止されなかったことを確認することができます彼らが終了する機会を得る前に中止されました:

Woke up after 4 sec. 

私は何をしたいのですか?

ここでもasyncioが必要なのかわかりませんが、おそらくconcurrent.futuresも使用できます。いずれの方法でもタスクは同じです。タスクを終了します。タスクの終了には時間がかかりすぎます。

答えて

0

あなたはProcess.terminate使用することができます

try: 
    yield from proc.wait() 
except asyncio.CancelledError: 
    proc.terminate() 
    raise 

または:私は見ていなかったのはなぜ

がasyncio.CancelledErrorは私のコードで育っ

try: 
    yield from proc.wait() 
finally: 
    if proc.returncode is None: 
     proc.terminate() 

EDITを?

asyncio.wait_for(または他のもの)がタスクをキャンセルすると、対応するコルーチンにCancelledErrorがスローされます。これにより、必要に応じてコルーチンがいくつかのクリーンアップを実行できるようになります(たとえば、コンテキストマネージャまたはtry/finally節を使用)。このエラーは、取り消されたタスクの通常の動作であるため、記録する必要はありません。しかし、それを取り消した後で仕事を待つようにしてください。CancelledErrorが起こります。

+0

本当に美しく働いた、ありがとう!私はちょうど、なぜ私は 'asyncio.CancelledError'が私のコードで生成されたのか分かりませんでした。示されているように、出力は例外なく、きれいでした。 –

+0

@NarūnasK私の編集を参照してください。 – Vincent

関連する問題