You can use asyncio
, where corotines / tasks ( Task
) are similar to threads but are not actually threads as defined by the OS, and therefore have no context-switching or external your own program.
Suppose you want to calculate the square of a list of numbers from 0 to 4, but you want to cancel the execution of the calculation of 2 ^ 2 if the result of some other function is 9, without having inside the calculation corotina no check as you asked.
If you do this with asyncio
:
import asyncio
import random
# Função que simula algum trabalho de cada tarefa/corotina (semelhante a uma thread)
async def retornar_quadrado(n):
if n == 2:
await asyncio.sleep(10) # A função que será cancelada demora mais.
else:
await asyncio.sleep(random.uniform(0.5, 2)) # As outras demoram de 0.5 a 2 segundos.
return n ** 2
async def main():
# Criar uma lista de tarefas
tarefas = []
for i in range(5):
tarefa = asyncio.ensure_future(retornar_quadrado(i))
tarefas.append(tarefa)
for tarefa_completa in asyncio.as_completed(tarefas):
try:
n_quadrado = await tarefa_completa
print(n_quadrado)
except asyncio.CancelledError:
continue
# Se descobrimos que uma das respostas é 9, cancelamos tarefas[2]
if n_quadrado == 9 and not tarefas[2].cancelled():
print('Cancelando tarefas[2]...')
tarefas[2].cancel()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
An example result:
16
9
Cancelando tarefas[2]...
0
1
As you can see, once we found 9, we canceled the calculation of 2 ^ 2 and it was never displayed. If you remove the tarefas[2].cancel()
line, you will see that the result 4
is displayed, and also that the function will take the 10 seconds that this special case requires.