metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2013-04-16 10:17 pm

Проклятая тема

Как известно, в программировании есть несколько проклятых тем. Т.е. задач, которые сами по себе просты, но их общего (повторно-используемого, кросс-платформенного, не заставляющего глаза течь кровью) решения не бывает и приходится каждый раз мутить какие-то велосипеды.
Одна из таких тем: прерывание длительных и блокирующих операций. Смежная - показ прогресса для таких операций. Вот, например, в контексте скалы: http://ru-scala.livejournal.com/36634.html
Почему эта тема проклята?
Во-первых, прерывание означает либо два потока, либо callback изнутри операции, вызывающий проверку наличия ввода от пользователя (Application.DoEvents/Application.ProcessMessages). Средний разработчик от многопоточности и callback бежит как от огня.
Во-вторых, i/o операции изначально сами по себе блокирующие. Всякие там чтения из сокетов, файлов(на сгнившей файловой системе примонтированной с выключенного сервера), rs232-портов с забытыми таймаутами и прочего зла. Реализация асинхронного i/o - жесточайшее уныние, что с overlapped, что с completion ports, что с select и прочими epoll.
В уютной сишечьке или недалеко от них ушедших C++ и Delphi - это по крайней мере, помещается в мозг, в дотнетах же, жабах, рантаймах хаскеля и прочих порождениях геенны огненной - либо авторы рантайма озаботились прерыванием операций, либо изобретение велосипеда вырождается в чад угара и лавирования между GC и разными уровнями представления данных.
Во-третьих, "у меня на столе все работает". Когда сервера не выключаются, сеть работает, диски без бэдов и железо отвечает вовремя - операции отрабатывают быстро, или можно их выполнять мелкими блоками и проверять какие-нибудь флаги отмены.

В-четверых, часто эти операции завернуты в десятки слоев чужих библиотек, например, "выполнение запроса к БД и выборка неизвестного количества миллионов записей, потому что база не знает сколько записей подпадает под условие". Если повезет - метод "прервать и свалится с исключением в потоке выполнения запроса" будет в API и даже после его применения внутренние структуры данных не превратятся в кашу. Если нет - то только убивать себя о стену.

[identity profile] http://users.livejournal.com/_slw/ 2013-04-16 07:28 pm (UTC)(link)
в rt-11 прерывание операций было сделанно и работало зашибись.
как и асинхронный ввод-вывод, кстати.

[identity profile] justy-tylor.livejournal.com 2013-04-16 07:53 pm (UTC)(link)
Свои таски, которые будут работать в параллельных тредах, кидать в очередь юзеринтерфейсного треда проценты выполнения, а также прерываться по команде - пишутся за день на любой привычной платформе. Почему из коробки на этих платформах только жабы и черви - вопрос философский.

Что же касается асинхронщины, то она вся на таких заплатках к говнопосиксу и винапи, что её не обернуть в разумную форму без потерь. А других ядер у нас нет.

[identity profile] falcrum.livejournal.com 2013-04-16 08:02 pm (UTC)(link)
Это да: задача "как корректно срубить зависший поток по таймауту" обычно... :(

[identity profile] vit-r.livejournal.com 2013-04-16 08:29 pm (UTC)(link)
Средний разработчик от многопоточности и callback бежит как от огня.

Средний разработчик об этом не знает. А если знает, то не правильно. Как-то в группе, делавшей реалтайм "на системе, которая всё берёт на себя", нашёлся только один человек, который, нет не проверил, а просто понял, что там с прерываниями и семафорами написано.

[identity profile] enternet.livejournal.com 2013-04-16 08:37 pm (UTC)(link)
Не вижу ничего проклятого. Есть правильные шаблоны разработки таких вещей. Просто правильность должна соблюдаться на всех уровнях реализации.

Примеры (от балды про винду):
низкий уровень - WaitForMultipleObjects и ваши волосы станут белыми. Может быть даже и пушистыми, но это уже как повезет - не все драйверы порождают все нужные события.
средний уровень - например, на винде в данный момент глупо писать свой TCP-сервер, потому как есть ряд системных сервисов, через которые все необходимое можно получить в готовом, высокопроизводительном виде.
высокий уровень - следование идеологии разработки таких вещей в выбранной среде и понимание её ограничений. Т.к. рантайм всегда ограничен.

[identity profile] w00dy.livejournal.com 2013-04-16 11:34 pm (UTC)(link)
Многопоточность, watchdog (убивающий подвисшие потоки, как самый крайний вариант) плюс делать таски чтобы они могли себя прерывать в определённых точках (проверять флаг). Если делал один раз, то ничего сложного имхо.

[identity profile] smalgin.livejournal.com 2013-04-17 03:27 am (UTC)(link)
Не нужно убивать себя об стену, нужно для каждой асинхронной операции четко выписать state change, после чего по таймауту тупо откатывать этот state change назад (rollback) или вперед (failure/failover/whatever). В большинстве случаев не нужно эмулировать транзакцию, достаточно, чтобы достигалось state consistency перед и после вызова, а это гораздо легче. Finite state machines, мать их. Само собой, если вдруг выяснится, что вызов какой-то функции имеет поганые и недокументированные side effects, то без убийства об стену не обойтись.... ну дак способом, как известно, цыган и хату спалил...

А уж как убивать по таймауту... лично я предпочитаю свои потоки. Приличного API темплейта для асинхронных вызовов не видел еще. Ну да я много чего в жизни не видел. Судя по вашей записи, вы тоже еще не видели.

[identity profile] sergiej.livejournal.com 2013-04-17 05:16 am (UTC)(link)
Просто если собрать толпу лучших разработчиков мира, и попросить согласовать как эта проблема должна решаться, то они скорее поубивают друг друга, чем найдут конценсус.

[identity profile] trueblacker.livejournal.com 2013-04-17 05:30 am (UTC)(link)
ящитаю, примитивный клиент-сервер на неблокирующих сокетах - обязательное упражнение для всякого программиста, претендующего на продвинутость

[identity profile] volodymir-k.livejournal.com 2013-04-17 06:15 am (UTC)(link)
> Во-вторых, i/o операции изначально сами по себе блокирующие.

В юниксе да.
В винде-нт изначально нет, сразу асинхронно, а для win32 сделали блокирующие прокладки.

> Реализация асинхронного i/o - жесточайшее уныние

Вкусовщина. Если у вас мозги заточены на read(buf) и больше не гнутся.

> callback изнутри операции, вызывающий проверку наличия ввода от пользователя (Application.DoEvents/Application.ProcessMessages).

Изучите, что такое флаги и как они могут выставляться.

Впрочем не надо, не будете конкурентом.