При работе с запросами без оператора with в качестве контекстного менеджера наблюдается странное поведение, которое приводит к постоянной блокировке ресурсов при использовании стандартного шаблона if req in res и того и другого. условия происходят симулировано следующим образом.
req = resource.request()
result = yield req | env.timeout(5) # req and timeout occurs simultaneously
if req in result:
# DO SOMETHING WITH RESOURCE
resource.release(req)
else:
req.cancel() # Important as req is still in resource queue and can be triggered after timeout, which is another possible cause of a resource being locked permanently
assert not req.triggered # Quirky behaviour here as req can be triggered at this point
После дальнейшего изучения я обнаружил, что в result хранятся только обработанные события, поэтому req может быть запущен, но еще не обработан (хотя я чувствую, что что запуск request() приводит к немедленной обработке, более интуитивно понятен), поэтому мы вводим блок кода else. После выполнения кода в блоке else запрос будет обработан, но поскольку выполнение кода уже прошло блок if, req остается висящим и невыпущенным. .
Изначально я думал, что req.cancel() достаточно, но похоже, что он не отменяет сработавшее событие (поправьте меня, если я ошибаюсь). . Таким образом, я придумал альтернативу, которая, по-видимому, устранила проблему.
# Rest of code
else:
req.cancel()
resource.release(req) # Doesn't feel right
(Я могу ошибаться, поэтому поправьте меня, если необходимо) Если req будет обработан позже, запланировано событие Release или, что эквивалентно, get позже и обязательно освободит ресурс, чтобы он не оставался висящим, и даже если req не было предоставлено, Release(req) не вызовет исключения.
Однако мне не понравился такой подход. По правде говоря, я должен оказаться в блоке if, если получу ресурс в заданное время моделирования, даже если фактическая обработка req происходит «позже» в очереди, что отражает фактическое поведение. Поэтому я попробовал другой метод, который, похоже, тоже работает...
# rest of code
if req.triggered:
# rest of code
else:
req.cancel()
# rest of code
Итак, как следует из названия статьи, является ли этот последний метод эквивалентным выполнению стандартного шаблона и, следовательно, безопасным? Будут ли при этом какие-либо опасности, поскольку я технически «пропускаю время», рассматривая запрос как обработанный до его фактической обработки (у меня нет случая, когда ресурс используется 0 раз, а затем освобождается , но было бы интересно узнать, может ли это быть проблемой)? Возможно, лучше найти способ переупорядочить события так, чтобы req обрабатывался первым, несмотря на то, что он был помещен в очередь позже, чем событие тайм-аута? Заранее большое спасибо!
Изменить: пример кода, демонстрирующий поведение.
import random
import simpy
def source(env, number, counter):
for i in range(number):
c = customer(env, counter)
env.process(c)
yield env.timeout(1)
def customer(env, counter):
patience = 5
while True:
req = counter.request()
results = yield req | env.timeout(patience)
print(f'req triggered = {req.triggered}, req processed = {req.processed}, req in result = {req in results}')
if req in results:
yield env.timeout(5)
counter.release(req)
break
else:
if req.triggered:
assert 0
req.cancel()
random.seed(42)
env = simpy.Environment()
counter = simpy.Resource(env, capacity=1)
env.process(source(env, 100, counter))
env.run(until=100)
Подробнее здесь: https://stackoverflow.com/questions/793 ... tead-of-if
При получении событий AnyOf безопасно ли использовать if req.triggered вместо if req in res? ⇐ Python
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Полиморфизм определения Spring Boot OpenAPI со свойством AnyOf и дискриминатора
Anonymous » » в форуме JAVA - 0 Ответы
- 12 Просмотры
-
Последнее сообщение Anonymous
-