против асинхронный неблокирующий

в чем разница между асинхронными и неблокирующими вызовами? Также между блокировкой и синхронными вызовами (с примерами, пожалуйста)?

12 ответов


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

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

но асинхронные сокеты (поддерживаемые сокетами Windows) или асинхронный шаблон ввода-вывода, используемый в .NET, более удобны. Вы вызываете метод для запуска операции, и фреймворк вызывает вас обратно, когда это будет сделано. Даже здесь есть основные различия. Асинхронные сокеты Win32 "маршалируют" свои результаты в определенный поток GUI, передавая сообщения окна, тогда как .NET асинхронный IO является свободным потоком (вы не знаете, что thread ваш обратный вызов будет вызван).

поэтому они не всегда означают одно и то же. Чтобы дистиллировать пример сокета, мы могли бы сказать:

  • блокировка и синхронность означают одно и то же: вы вызываете API, он зависает в потоке, пока не получит какой-то ответ и не вернет его вам.
  • non-blocking означает, что если ответ не может быть возвращен быстро, API немедленно возвращается с ошибкой и больше ничего не делает. Поэтому должен быть какой-то связанный способ запросите, готов ли API к вызову (то есть, чтобы эффективно имитировать ожидание, чтобы избежать ручного опроса в узком цикле).
  • асинхронный означает, что API всегда возвращается немедленно, запустив "фоновое" усилие для выполнения вашего запроса, поэтому должен быть какой-то связанный способ получить результат.

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

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

  • одна интерпретация заключается в том, что вызов будет делать что-то в фоновом режиме, по существу, неконтролируемым, чтобы позволить программе не задерживаться длительным процессом, который ей не нужно контролировать. Воспроизведение аудио может быть примером-программа можно вызвать функцию для воспроизведения (скажем) mp3, и с этого момента можно продолжить другие вещи, оставив его в ОС для управления процессом рендеринга звука на звуковом оборудовании.
  • альтернативная интерпретация заключается в том, что вызов будет делать то, что программа должна будет контролировать, но позволит большей части процесса происходить в фоновом режиме только уведомляя программу в критические моменты процесса. Например, асинхронный файл IO может быть примером - программа предоставляет буфер операционной системе для записи в файл, а ОС уведомляет программу только о завершении операции или возникновении ошибки.

в любом случае, намерение состоит в том, чтобы позволить программе не быть заблокированной в ожидании медленного процесса для завершения - как программа, как ожидается, ответит единственная реальная разница. Какой термин относится к которому также меняется от программиста к программисту, языка к языку или платформы к платформе. Или условия может ссылаться на совершенно разные понятия (например, использование синхронного/асинхронного по отношению к потоковому программированию).

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


постановка этого вопроса в контексте NIO и NIO.2 в java 7 асинхронный ввод-вывод на один шаг более продвинутый, чем неблокирующий. С неблокирующими вызовами java NIO можно установить все каналы (SocketChannel, ServerSocketChannel, FileChannel и т. д.) Как таковые, вызвав AbstractSelectableChannel.configureBlocking(false). Однако после возврата этих вызовов ввода-вывода вам, вероятно, все равно придется контролировать проверки, такие как если и когда читать/писать снова и т. д.
Например,

while (!isDataEnough()) {
    socketchannel.read(inputBuffer);
    // do something else and then read again
}

с асинхронным api в java 7, эти элементы управления могут быть выполнены более универсальными способами. Один из 2 способов-использовать CompletionHandler. Обратите внимание, что оба read вызовы не блокируются.

asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */, 
    new CompletionHandler<Integer, Object>() {
        public void completed(Integer result, Object attachment) {...}  
        public void failed(Throwable e, Object attachment) {...}
    }
}

синхронный / асинхронный-это описание отношения между двумя модулями.
блокировка / неблокирование-это описание ситуации одного модуля.

пример:
Модуль X: "I".
Модуль Y: "книжный магазин".
X спрашивает Y: у вас есть книга под названием "C++ primer"?

1) блокировка: прежде чем Y отвечает X, X продолжает ждать ответа. Теперь X (один модуль) блокируется. X и Y-это два потока или два процесса или один поток или один процесс? мы не знаем.

2) non-blocking: прежде чем Y отвечает X, X просто уходит и делает другие вещи. X может возвращаться каждые две минуты, чтобы проверить, закончил ли Y свою работу? Или X не вернется, пока Y не позвонит ему? Мы не знаем. мы знаем только, что X может делать другие вещи, прежде чем Y закончит свою работу. Здесь X (один модуль) не блокируется. X и Y - это два потока или два процесса или один процесс? мы не знаем. Но мы уверены, что X и Y не могут быть одним нитка.

3) синхронно: прежде чем Y отвечает X, X продолжает ждать ответа. Это означает, что X не может продолжаться, пока Y не закончит свою работу. Теперь мы говорим: X и Y (два модуля) синхронны. X и Y-это два потока или два процесса или один поток или один процесс? мы не знаем.

4) асинхронный: прежде чем Y ответит X, X уйдет оттуда, и X может выполнять другие задания. X не вернется, пока Y не позвонит ему. теперь мы говорим: X и Y (два модуля) асинхронный. X и Y - это два потока или два процесса или один процесс? мы не знаем. Но мы уверены, что X и Y не могут быть одним потоком.


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

вот типичный пример неблокирующего & синхронно:

// thread X
while (true)
{
    msg = recv(Y, NON_BLOCKING_FLAG);
    if (msg is not empty)
    {
        break;
    }
    sleep(2000); // 2 sec
}

// thread Y
// prepare the book for X
send(X, book);

Вы можете увидеть, что эта конструкция является неблокирующей (можно сказать, что большую часть времени этот цикл что-то делает глупость, но в ЦП глаза, выполняется X означает, что X является неблокируемой), а X и y являются синхронными, потому что Х не может продолжать делать все (х не может выскочить из петли), пока не получит книгу от Ю.
Обычно в этом случае блокировка X намного лучше, потому что неблокирующая тратит много ресурсов на глупый цикл. Но этот пример полезно помочь вам понять тот факт, что неблокирование не означает асинхронность.

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

например, мы можем спроектировать такую архитектуру:

// Module X = Module X1 + Module X2
// Module X1
while (true)
{
    msg = recv(many_other_modules, NON_BLOCKING_FLAG);
    if (msg is not null)
    {
        if (msg == "done")
        {
            break;
        }
        // create a thread to process msg
    }
    sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");


// Module Y
// prepare the book for X
send(X, book);

в этом примере, мы можем сказать, что

  • Х1 неблокирующий
  • X1 и X2 синхронны
  • X и Y являются асинхронными

Если вам нужно, вы также можете описать эти потоки, созданные в X1, четырьмя словами.

более важные вещи: когда мы используем синхронные, а не асинхронные? когда мы используем блокировку вместо неблокирующей?

почему Nginx не блокирует? Почему Apache блокирует?

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


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

An асинхронные вызов запрашивает передачу, которая будет выполнена полностью (полностью), но завершится в будущем.


неблокирующий: эта функция не будет ждать, пока в стеке.

асинхронный: работа может продолжаться от имени вызова функции после того, как этот вызов покинул стек


блокировка call: Control возвращается только после завершения вызова.

неблокирующее вызов: управление возвращается немедленно. Позже ОС каким-то образом уведомляет процесс, что вызов завершен.


синхронно программа: программа, которая использует блокировка звонки. Чтобы не замерзнуть во время вызова, он должен иметь 2 или более потоков (поэтому он называется синхронным-потоки работают синхронно.)

асинхронные программа: программа, которая использует неблокирующее звонки. Он может иметь только 1 поток и по-прежнему оставаться интерактивным.


синхронно определяется как происходящее одновременно.

асинхронные определяется как не происходит одновременно.

Это то, что вызывает сначала недоумение. Синхронность-это то, что известно как параллель. Пока асинхронный является последовательным, сделайте это, затем сделайте это.

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

самое простое решение известно как блокировка.

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

поэтому, если вам нужно положить масло на тост, и, таким образом, вам сначала нужно тост разводить. То, как вы координируете их, - это то, что вы сначала поджарьте тост, затем бесконечно смотрите на тостер, пока он не выскочит тост, а затем вы продолжите намазывать их маслом.

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

вот где вступают в игру два других решения, известных соответственно как неблокирующие и асинхронные.

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

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

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

здесь приходит асинхронный.

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

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

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

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

В заключение, хорошо понимать, что в то время как неблокирующий и асинхронный (или то, что я предпочитаю называть evented) позволяют вам делать другие вещи, пока вы ждете, у вас тоже нет. Вы можете выбрать постоянный цикл проверки состояния неблокирующего вызова, не делая ничего другого. Это часто хуже, чем блокировка (например, глядя на тостер, затем прочь, а затем обратно на него, пока он не сделает), поэтому многие неблокирующие API позволяют вам переходить в режим блокировки от него. Для evented вы можете просто подождать, пока вас не уведомят. Недостатком в этом случае является то, что при добавлении уведомление сложный и потенциально дорогостоящий. Вам нужно было купить новый тостер с функцией звукового сигнала или убедить своего партнера посмотреть его за вас.

и еще одна вещь, вам нужно понять, что компромиссы все три обеспечивают. Один явно не лучше других. Подумайте о моем примере. Если ваш тостер так быстр, у вас не будет времени вымыть посуду, даже начать мыть ее, вот как быстр ваш тостер. В таком случае начинать что-то другое-пустая трата времени. и усилия. Блокировка подойдет. Аналогично, если мытье посуды займет в 10 раз больше времени, то тосты. Вы должны спросить себя, что важнее сделать? Тост может стать холодным и жестким к тому времени, не стоит того, блокировка также будет делать. Или вы должны выбрать более быстрые вещи, чтобы сделать, пока вы ждете. Там более очевидно, но мой ответ уже довольно длинный, моя точка зрения, что вам нужно подумать обо всем этом, и сложности реализации каждого, чтобы решить, стоит ли это того, и если это будет на самом деле улучшите свою производительность.

изменить:

хотя это уже давно, я также хочу, чтобы он был завершен, поэтому я добавлю еще два пункта.

1) Существует также обычно четвертая модель, известная как мультиплексированных. Это когда, пока вы ждете одну задачу, вы начинаете другую, и пока вы ждете обе, вы начинаете еще одну и так далее, пока у вас не будет много задач, которые все запущены, а затем вы ждете простоя, но на всех их. Поэтому, как только что-либо будет сделано, вы можете приступить к обработке его ответа, а затем вернуться к ожиданию других. Это называется мультиплексированием, потому что пока вы ждете, вам нужно проверить каждую задачу одну за другой, чтобы увидеть, выполнены ли они, ad vitam, пока одна не будет выполнена. Это немного расширение поверх обычного неблокирующего.

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

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

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


Они отличаются только орфографией. Нет никакой разницы в том, к чему они относятся. Чтобы быть техническим, вы могли бы сказать, что они отличаются акцентом. Non blocking относится к потоку управления(он не блокирует.) Асинхронный относится к тому, когда обрабатывается событие\данные (не синхронно.)


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


блокирование: control возвращается к вызову precess после завершения обработки примитива (sync или async)

неблокирующее: управление возвращается сразу после вызова