В чем разница между асинхронным программированием и многопоточностью?

Я думал, что это в основном одно и то же - написание программ, которые разделяют задачи между процессорами (на машинах с 2+ процессорами). Затем я читаю https://msdn.microsoft.com/en-us/library/hh191443.aspx , где написано

  

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

     

Ключевые слова async и await не приводят к созданию дополнительных потоков   создано. Асинхронные методы не требуют многопоточности, потому что асинхронные   метод не работает в своем собственном потоке. Метод работает на текущем   контекст синхронизации и использует время в потоке, только когда   метод активен. Вы можете использовать Task.Run для перемещения работы с процессором в   фоновый поток, но фоновый поток не помогает с процессом   это только ожидание результатов, чтобы стать доступными.

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

Теперь я понимаю идею асинхронных задач, таких как пример на pg. 467 из C # In Depth, третьего издания Джона Скита

async void DisplayWebsiteLength ( object sender, EventArgs e )
{
    label.Text = "Fetching ...";
    using ( HttpClient client = new HttpClient() )
    {
        Task<string> task = client.GetStringAsync("http://csharpindepth.com");
        string text = await task;
        label.Text = text.Length.ToString();
    }
}

Ключевое слово async означает «. Эта функция, когда бы она ни вызывалась, не будет вызываться в контексте, в котором ее завершение требуется для всего после вызова его вызова. "

Другими словами, писать это в середине какого-то задания

int x = 5; 
DisplayWebsiteLength();
double y = Math.Pow((double)x,2000.0);

, поскольку DisplayWebsiteLength() не имеет ничего общего с x или y, вызовет DisplayWebsiteLength() должен выполняться "в фоновом режиме", как

                processor 1                |      processor 2
-------------------------------------------------------------------
int x = 5;                                 |  DisplayWebsiteLength()
double y = Math.Pow((double)x,2000.0);     |

Очевидно, что это глупый пример, но я прав, или я полностью запутался или что?

(Кроме того, я не совсем понимаю, почему sender и e никогда не используются в теле вышеуказанной функции.)

115 голосов | спросил user5648283 8 Jpm1000000pmFri, 08 Jan 2016 18:53:02 +030016 2016, 18:53:02

1 ответ


0

Встроенный в браузер Javascript - отличный пример асинхронной программы без потоков.

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

Однако, когда выполняется что-то вроде AJAX-запроса, код вообще не выполняется, поэтому другой javascript может реагировать на такие вещи, как события click, пока этот запрос не вернется и не вызовет обратный вызов, связанный с ним. Если один из этих других обработчиков событий все еще работает, когда возвращается запрос AJAX, его обработчик не будет вызываться, пока они не будут выполнены. Работает только одна «нить» JavaScript, даже если вы можете эффективно приостановить то, что вы делали, до тех пор, пока у вас не появится нужная информация.

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

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

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

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

До тех пор, пока не были добавлены ключевые слова async/await, в C # было гораздо более очевидно, как вызывается код обратного вызова, потому что эти обратные вызовы были в форме делегатов, которые вы связали с задачей. Чтобы по-прежнему давать вам преимущество использования операции ...Async(), избегая при этом сложности в коде, async/await абстрагирует создание этих делегатов. Но они все еще есть в скомпилированном коде.

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

ответил StriplingWarrior 8 Jpm1000000pmFri, 08 Jan 2016 19:01:05 +030016 2016, 19:01:05

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132