Python - Почему мое исключение тайм-аута всегда выполняется - PullRequest
0 голосов
/ 22 июня 2019

Я пытаюсь понять библиотеку Python asyncio, и у меня возникла проблема с исключением из-за тайм-аута. Я не могу понять, почему исключение «asyncio.TimeoutError» в функции «async def create» всегда выполняется в конце моей программы, даже если предел тайм-аута не прошел. Буду признателен Вашему совету и мнению эксперта :) 1001 *

Спасибо за ваше время.

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

1 Ответ

1 голос
/ 22 июня 2019

В create() вы вызываете исключение сразу после ожидания выполнения задач x,y,z. Добавление нескольких отпечатков к toaster и create показывает, что три задачи заканчиваются, поэтому выполнение просто возобновляется с оператором raise asyncio.TimeoutError....

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

Результаты в

>>>
...
...
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

  • Я вставил 3 тоста и сначала выбросил их запрос .
  • Я прошел дюжину циклов впрыскивания и извлечения тоста, и он этого не делал тайм-аут, но исключение было поднято, как только отказался ввести больше тостов.

...why does the "asyncio.TimeoutError" exception in the "async def create" function always execute at the end of my program ...?
Я бы сказал, что вы написали это для этого - похоже, это было ваше намерение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...