Для того, чтобы предположить, на улучшение скорости из-за какой-либо форме мульти-вычисления необходимо предположить, что либо несколько задач ЦП на основе в настоящее время выполняются одновременно на нескольких вычислительных ресурсов (как правило, процессорных ядер), либо, что не все задачи зависят от одновременного использования одного и того же ресурса, то есть некоторые задачи могут зависеть от одного подкомпонента системы (например, дискового хранилища), тогда как некоторые задачи зависят от другого (получение связи с периферийного устройства), а третьи могут потребовать использование процессорных ядер.
Первый сценарий часто называют «параллельным» программированием.Второй сценарий часто называют «параллельным» или «асинхронным» программированием, хотя иногда используется «одновременный», чтобы ссылаться на случай просто позволяя операционной системе чередовать выполнение нескольких задач независимо от того, должно ли это выполнение размещать поочередно или если для достижения параллельного выполнения можно использовать несколько ресурсов. В этом последнем случае «одновременный» обычно относится к тому, как выполнение записывается в программе, а не с точки зрения фактической одновременности выполнения задачи.
Очень легко говорить обо всем этом с молчаливыми предположениями. Например, некоторые из них быстро заявляют, например: «Асинхронный ввод-вывод будет быстрее, чем многопоточный ввод-вывод». Это утверждение сомнительно по нескольким причинам. Во-первых, это может быть случай, когда какая-то заданная асинхронная инфраструктура ввода-вывода реализована точно с многопоточным потоком, и в этом случае они одни и те же, и нет смысла говорить, что одна концепция «быстрее, чем другая» ,
Во-вторых, даже в случае однопоточной реализации асинхронной структуры (такой как однопоточный цикл событий) вы все равно должны делать предположение о том, что делает этот цикл. Например, одна глупая вещь, которую вы можете сделать с однопоточным циклом событий, - это запрос для асинхронного завершения двух разных задач, связанных с ЦПУ. Если вы сделали это на машине с только идеализированным однопроцессорным ядром (игнорируя современную аппаратную оптимизацию), выполнение этой задачи «асинхронно» на самом деле не будет выполняться иначе, чем выполнение с двумя независимо управляемыми потоками или только с одним одиночным процессом - - разница может снизиться до оптимизации контекста потока или оптимизации расписания операционной системы, но если обе задачи будут направлены в CPU, это будет похоже в любом случае.
Полезно представить себе множество необычных или глупых угловых дел, в которые вы могли бы столкнуться.
«Асинхронный» не должен быть одновременно, например, как и выше: вы «асинхронно» выполняете две задачи, связанные с процессором, на машине с ровно одним ядром процессора.
Многопоточное исполнение не обязательно должно быть одновременным: вы создаете два потока на машине с одним процессорным ядром или попросите два потока получить любой другой дефицитный ресурс (предположим, скажем, сетевую базу данных, которая может устанавливать только одно соединение за раз). Выполнение потоков может быть interleaved, однако планировщик операционной системы считает нужным, но их общая продолжительность выполнения не может быть уменьшена (и будет увеличена из переключения контекста потока) на одном ядре (или, более общо, если вы создаете больше потоков, чем есть ядра для их запуска или больше потоков, требующих ресурса, чем то, что может поддерживать ресурс). То же самое относится и к многопроцессорной обработке.
Таким образом, ни асинхронный ввод-вывод, ни многопоточность не должны обеспечивать прирост производительности в терминах времени выполнения. Они могут даже замедлить ход событий.
Если вы определите конкретный вариант использования, как определенную программу, которая делает сетевой вызов для извлечения данных из сетевого ресурса, такого как удаленная база данных, а также выполняет некоторые локальные вычисления, связанные с ЦП, то вы можете начните рассуждать о различиях в производительности между этими двумя методами, учитывая особое предположение об оборудовании.
Вопросы, которые необходимо задать: сколько вычислительных шагов мне нужно выполнить и сколько независимых систем ресурсов есть для их выполнения? Существуют ли подмножества вычислительных шагов, которые требуют использования независимых подкомпонентов системы и могут выиграть от этого одновременно? Сколько процессорных ядер у меня есть и какие накладные расходы для использования нескольких процессоров или потоков для выполнения задач на отдельных ядрах?
Если ваши задачи в значительной степени зависят от независимых подсистем, тогда асинхронное решение может быть хорошим.Если количество потоков, необходимых для его обработки, было бы большим, так что переключение контекста стало нетривиальным для операционной системы, тогда однопотоковое асинхронное решение могло бы быть лучше.
Когда задачи связаны одним и тем же ресурс (например, несколько потребностей, чтобы одновременно получить доступ к той же сети или локальному ресурсу), то многопоточность, вероятно, вводить неудовлетворительные накладные расходы, и в то время как в однопоточной асинхронности может вводить меньше накладные расходы , в такой ситуации с ограниченным ресурсом она тоже не может произвести ускорение. В таком случае единственная опция (если вы хотите ускорить) состоит в том, чтобы сделать несколько копий этого ресурса доступными (например, несколько процессорных ядер, если дефицитный ресурс - это ЦП, лучшая база данных, которая поддерживает более параллельные соединения, если дефицитный ресурс это база данных с ограниченным доступом и т. д.).
Другой способ поместить это: позволяет операционной системе чередовать использование одного ресурса для двух задач не может быть быстрее, чем просто дать одну задачу использовать ресурс в то время как другие ожидания, затем давая вторую закончить задачу серийно. Кроме того, стоимость планировщика перемежения в любой реальной ситуации фактически создает замедление. Не имеет значения, происходит ли чередование использования процессора, сетевого ресурса, ресурса памяти, периферийного устройства или любого другого системного ресурса.
короткий ответ: это больше связано с накладными расходами на наличие резьбы на соединение. non-blocking io позволяет избежать наличия потока на соединение. –
Блокировка IO стоит дорого в системе, где вы не можете создать столько потоков, сколько существует. На JVM вы можете создать несколько тысяч потоков, но что, если у вас более 100 000 соединений? Поэтому вы должны придерживаться асинхронного решения. Однако существуют языки, где потоки не дорогие (например, зеленые потоки), например, в Go/Erlang/Rust, где нет проблем иметь 100 000 потоков. Когда число потоков может быть большим, я считаю, что блокирование ввода-вывода дает более быстрое время ответа. Но это то, что я также должен был бы спросить у экспертов, правда ли это в действительности. – OlliP
@OliverPlow, я тоже так думаю, потому что блокирование ввода-вывода обычно означает, что мы позволяем * системе * обрабатывать «параллельное управление», вместо того чтобы делать это сами, используя очереди задач и т. Д. – Pacerier