Асинхронный и неблокирующий

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

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

2) неблокирующая: прежде чем 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 может не продолжайте делать другие вещи (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);

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

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

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

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

С асинхронным api в java 7 эти элементы управления могут быть сделаны более универсальными способами. Один из двух способов - использовать 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) {...}
    }
}

Ответ 6

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

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

Ответ 7

Неблокирование: эта функция не будет ждать в стеке.

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

Ответ 8

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

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


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

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

Ответ 9

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Редактировать:

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

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

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

Блокировка: управление возвращает к вызову прецессии после обработки примитива (синхронизация или асинхронный) завершает

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