Reputation: 1
I am attempting to grasp Python's asyncio library, and I'm having a problem with it's timeout exception. I can't figure out why does the "asyncio.TimeoutError" exception in the "async def create" function always execute at the end of my program even though the timeout limit hasn't passed. I would appreciate Your expert advise and opinion :)
Thank you for your time.
import asyncio
import multiprocessing as mp
from enum import Enum
class Sensor(Enum):
GREEN = 0
RED = 1
class State(Enum):
NORMAL = 0
MEDIUM = 1
BURNED = 2
class Toaster:
def __init__(self, min = 20, max = 50, temp = 0, timer = 0, state = State.NORMAL, sensor = Sensor.GREEN):
self.min = min
self.max = max
self.temp = self.min
self.timer = timer
self.state = state
self.sensor = sensor
def display(self):
print("\nTimer state:", self.timer, "seconds")
print("Toast state:", self.state.name)
print("Sensor state:", self.sensor.name)
async def start(self):
while True:
if self.temp <= self.max:
await asyncio.sleep(0.1)
print("Temperature:", self.temp)
self.temp+=1
else:
print("\nMaximum temperature", self.max, "celsius reached")
await self.measure_state()
await self.restart()
break
async def restart(self):
while True:
if self.temp >= self.min:
await asyncio.sleep(0.1)
print("Temperature:", self.temp)
self.temp-=1
else:
self.sensor = Sensor.GREEN
print("\nMinimum temperature", self.min, "celsius reached")
break
async def validateInput(self, message):
valid = False
while not valid:
try:
userInput = int(input(message))
if userInput == 0 or userInput == 1:
valid = True
return userInput
else:
raise ValueError("\nInvalid value", userInput)
except ValueError as v:
print(v)
async def eject(self):
self.display()
message = "\nEject toast - 1(Yes), 0(No):"
try:
return await asyncio.wait_for(self.validateInput(message), timeout=1000)
except asyncio.TimeoutError:
print("Took too long - eject")
async def repeat(self):
message = "\nInject another toast - 1(Yes), 0(No):"
try:
return await asyncio.wait_for(self.validateInput(message), timeout=1000)
except asyncio.TimeoutError:
print("Took too long - repeat")
async def measure_state(self):
while True:
await asyncio.sleep(5)
self.timer+=50
if self.timer == 50:
print("\nToast is in it's", self.state.name, "state")
if await self.eject() == 1:
print("\nToast ejected")
if await self.repeat() == 1:
self.timer = 0
self.state = State.NORMAL
await self.measure_state()
break
elif self.timer == 100:
self.state = State.MEDIUM
self.sensor = Sensor.RED
print("\nToast is in it's", self.state.name, "state")
if await self.eject() == 1:
print("\nToast ejected")
if await self.repeat() == 1:
self.timer = 0
self.state = State.NORMAL
await self.measure_state()
break
elif self.timer >= 150:
self.state = State.BURNED
print("\nToast is in it's", self.state.name, "state, ejecting toast")
break
async def toaster(self):
message = "\nInsert a toast - 1(Yes), 0(No):"
while await self.validateInput(message) != 1:
print("\nPlease insert a toast")
print("\nToast inserted")
await self.start()
async def create(self):
x = loop.create_task(Toaster().toaster())
y = loop.create_task(Toaster().toaster())
z = loop.create_task(Toaster().toaster())
try:
await asyncio.wait([x, y, z], timeout=1000)
raise asyncio.TimeoutError("\nTook too long - create")
except asyncio.TimeoutError as t:
print(t)
x.cancel(), y.cancel(), z.cancel()
def get_process_count():
nproc = mp.cpu_count()
pool = mp.Pool(processes=nproc)
return pool
class Connector(Toaster):
pass
async def main():
connector = Connector()
result = get_process_count()
result.map(await connector.create())
await asyncio.gather(result)
if __name__ == "__main__":
loop = None
try:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
except Exception as e:
pass
finally:
loop.close()
Upvotes: 0
Views: 320
Reputation: 23753
In create()
you raise the exception immediately after waiting for tasks x,y,z
to complete. Adding some prints to toaster
and create
shows that the three tasks finish so execution just resumes with the raise asyncio.TimeoutError...
statement.
...
async def toaster(self):
message = "\nInsert a toast - 1(Yes), 0(No):"
while await self.validateInput(message) != 1:
print("\nPlease insert a toast")
print("\nToast inserted")
await self.start()
return 'FINISHED'
async def create(self):
x = loop.create_task(Toaster().toaster())
y = loop.create_task(Toaster().toaster())
z = loop.create_task(Toaster().toaster())
try:
await asyncio.wait([x, y, z], timeout=1000)
for thing in (x,y,z):
print(thing)
raise asyncio.TimeoutError("\nTook too long - create") # <-- you raise the exception Here!
except asyncio.TimeoutError as t:
print(t)
x.cancel(), y.cancel(), z.cancel()
Results in
>>>
...
...
Temperature: 20
Minimum temperature 20 celsius reached
Temperature: 20
Minimum temperature 20 celsius reached
Temperature: 20
Minimum temperature 20 celsius reached
<Task finished coro=<Toaster.toaster() done, defined at tmp.py:129> result='FINISHED'>
<Task finished coro=<Toaster.toaster() done, defined at tmp.py:129> result='FINISHED'>
<Task finished coro=<Toaster.toaster() done, defined at tmp.py:129> result='FINISHED'>
Took too long - create
...why does the "asyncio.TimeoutError" exception in the "async def create" function always execute at the end of my program ...?
I would say you wrote it to do that - looks like that was your intention.
Upvotes: 1