LINUX.ORG.RU

критик реквест

 , , , ,


0

1

Разродился вот этим:

async def wait_event(add_callback, del_callback):                                                    
     ev = asyncio.Event()                                                                             
     def callback(*args, **kwargs):                                                                   
         ev.set()                                                                                     
     add_callback(callback)                                                                           
     await ev.wait()                                                                                  
     del_callback(callback)

...

await wait_event(my_class.add_some_event_listener, my_class.del_some_event_listener)

my_class - библиотечный класс из того же проекта. Переводить some_event на async не хочется, т.к. в некоторых юз кейсах важен порядок обработки ивентов (а в некоторых нет, а в других достаточно дождаться однократного ивента, как в примере выше).

Но детектор говнокода попискивает. Расскажите, как надо. Стоит ли в API класса на каждый event_listener добавить свой async def wait_event()?

Синтаксис async/await использую ~третий раз в жизни

Язык это только инструмент записи спеки. Если в архитектуре бардак (может так, может эдак, и вообще по-всякому), как это ни запиши красиво, детектор будет попискивать. Чем лучше язык, тем стремнее будет код.

pon4ik ★★★★★ ()
Ответ на: комментарий от anonymous

Ну, это всё конечно субъективщина, но. Имхо, лучший язык и/или фреймворк тот - который сопротивляется откровенно неудачным архитектурным решениям. Индикатором является так называемый говнокод, чем говёнее получается код при кривой архитектуре, тем лучше язык.

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

UPD: таки придумал относительно релевантный и достаточно показательный пример. rust и многопоточка. Насколько я слышал компилятор даст по рукам если не защитить данные на которых возможна гонка. Хотя, это тоже не то, это именно поддержка конкретной дисциплины, а не общая выразительность и «это можно сделать минимальным количеством способов».

pon4ik ★★★★★ ()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от pon4ik

Строителем Машин Состояний

нее, не думаю.

some_class - это по сути как раз парсер логов в реальном времени, точнее, результат работы парсера логов. но это только часть проекта.

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

структура проекта примерно такая сейчас:

[async LogParsers] => [sync State some_class] => [sync/async user classes]*

по мере поступления данных из логов, State some_class изменяется, и уведомляет подписчиков о своих изменениях

еще добавлю, что user classes могут подписываться на уведомления от других юзер классов, наравне с уведомлениями от some_class, хотя не думаю, что это существенно

MyTrooName ★★★★★ ()
Последнее исправление: MyTrooName (всего исправлений: 2)
Ответ на: комментарий от MyTrooName

Ну т.е. кажется, что у тебя просто список параллельно работающих конечных автоматов, каждый - со своим состоянием и условиями его изменения. Таблица переходов должна быть инкапсулированна по идее. Да они шарят часть по чтению входа, даже могут шарить очередь событий на барьере например или просто копируя ссылки. Но знать о условиях достижении одного из конечных состояний казалось бы должны только они.

Было бы интересно услышать сутевой кейс какой-то. Типа ждём в логе завершение старта приложения, обновления состояния, и т.п.

Кстати, если не секрет, почему не взял просто pexpect? Там качественно на мой взгляд проработан этот интерфейс, при условии что можно парсить регулярками. Хотя, возможно это чуть ближе к реализации, а нужен ещё какой то сахар сверху?

pon4ik ★★★★★ ()

Ещё одно замечание - безусловное ожидание, тоже обычно хорошо не заканчивается. Нужен таймаут, не знаю упрощения для ты так сделал, или и правда собираешься ждать события вечно?

pon4ik ★★★★★ ()
Ответ на: комментарий от pon4ik

конечных автоматов

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

сутевой кейс

ну например, выделяем из логов числа, рисуем в gui график. при перезагрузке (wait_event(add_reset_listener,del_reset_listener)) начинаем рисовать график заново

pexpect

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

MyTrooName ★★★★★ ()
Последнее исправление: MyTrooName (всего исправлений: 1)
Ответ на: комментарий от pon4ik

Нужен таймаут

ну, это же не единственный таск в пуле. пусть ждет хоть сутки, рано или поздно дождется.

какой-нибудь альтернативный флаг останова потом добавлю - но это будет скорее по команде от пользователя (закрытие окна с графиком), а не по таймауту

MyTrooName ★★★★★ ()
Последнее исправление: MyTrooName (всего исправлений: 2)
Ответ на: комментарий от MyTrooName

в питоне нельзя как в браузере сделать. в браузере цикл обработки событий встроенный. в твоем классе должен быть метод listen, который будет ожидать сообщения из сокета и генерировать событие fire(event, *args, **kw)

tz4678 ()
Ответ на: комментарий от tz4678

чиво? какого сокета? откуда ты взял браузер, и почему в питоне нельзя сделать как в браузере? и ты в курсе, что такое asyncio?

MyTrooName ★★★★★ ()
Последнее исправление: MyTrooName (всего исправлений: 2)
Ответ на: комментарий от MyTrooName

ржу. я то в курсе.

в браузере ты пишешь типа такого const ws=new WebSockets… ws.onmessage = e =>… и все как только к тебе приходит сообщение, вызвается каллбек. а в питоне все через генераторы сделано и ты должен итерацию делать. короче не вижу смысла натруждать себя объясняя очевидное.

tz4678 ()