Подтвердить что ты не робот

Написание кода, поддерживаемого событиями

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

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

Я понимаю, что я новичок в этом мышлении развития, и не все мои объектно-ориентированные заботы переносятся. Существуют ли какие-либо ресурсы для написания поддерживаемого, понятного кода, управляемого событиями? Что делают люди, которые используют node.js или Twisted или Event Machine?

4b9b3361

Ответ 1

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

Twisted python допускает очень императивный стиль, используя либо inlinecallbacks, либо (слегка уродливые) отложенные стили генератора. Эти методы позволяют вам писать процедуры, которые используют код обратного вызова, управляемый событиями, который намного легче читать и понимать. Реализация превращает вашу функцию в ленивую последовательность, которая дает последовательность отсрочек.

В частности, вам не нужно создавать глубоко вложенный набор функций обратного вызова /lambdas/closures и вместо этого вместо этого управлять контролем функции в цикле событий в произвольных точках. Вы можете мысленно перемаркировать это как сопрограммы или совместную многозадачность, если хотите. Он выполняет свою работу. Примером может быть (используя более уродливый стиль отложенного генератора) следующим образом:

@defer.deferredGenerator
def foo(arg):
    bar = nonBlockingFunction(foo)
    baz = waitForDeferred(aFunctionThatReturnsADeferredToo(bar))
    yield baz #Returns control to the event loop
    output = baz.getResult() #This gets the output of aFunctionThat...Too above
    yield output #This is how we return a result instead of using return

@defer.deferredGenerator
def aFunctionThatReturnsADeferredToo(put_bar_here):
    """Stuff happens here...."""
    ...etc...

Здесь есть еще одно сообщение, в котором показан метод inlineCallbacks, который является более чистым, но требует python 2.5 или новее (что не означает, что Centos/RHEL 5 серии, к которым я печально привязана к моему приложению). Если вы можете использовать его, DO SO.

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

Что касается отладки, вы можете включить отладку открученного реактора, используя вызов defer.setDebugging(True) где-то в вашем коде инициализации. Это приложит исходную трассировку, которая вызвала бы исключение в вашем коде, чтобы вы могли тривиально увидеть, где произошла ошибка ACTUALLY. Просто не забудьте отредактировать оператор setDebugging перед тем, как начать производство, потому что это приводит к ОГРОМНОЙ сумме дополнительной интроспекции (смотрите ее в strace, если хотите, чтобы вы были в ужасе).

Ответ 4

Мартин Лофран написал превосходную короткую статью полностью об избежании спагетти обратного вызова.

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

Ответ 5

Для Twisted, вместо использования старого отложенного генератора, я рекомендую inlineCallbacks; Он позволяет полностью писать код стиля блокировки и по-прежнему хорошо воспроизводить цикл событий.

@defer.inlineCallbacks
def foo(arg):
    bar = nonBlockingFunction(foo)
    output = yield FunctionThatReturnsADeferredToo(bar)
    defer.returnValue(output) #This is how we return a result instead of using return

Ответ 6

Очевидно, что есть уже лучшие практики и модели, которые будут продолжать развиваться с течением времени.

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

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

Просмотрите веб-крючки и посмотрите, как такие службы, как Twilio уже работают

Ответ 7

Мой единственный совет - думать о функциях.