То, что я хочу реализовать в своей программе, – это следующий столбец / рабочий процесс:
Моя идея состояла в том, что httpPost()
будет асинхронным, а остальные 2 метода остаются несинхронными. Однако по какой-то причине это не сработало бы для меня, если бы я не сделал 2. + 3. asynchronous. Может быть, у меня все еще есть недоразумения.
Насколько я понимаю, я могу либо a) использовать await
-keyword при вызове метода async (это приведет к приостановке метода и продолжению после завершения асинхронного метода), либо b) опустить await
-keyword и вместо этого вызвать Task.Result async методы возвращают значение, которое будет блокироваться до тех пор, пока результат не будет доступен.
Позвольте мне показать вам рабочий пример:
private int dispatch(string options) { int res = authorize(options).Result; return res; } static async private Task authorize(string options) { string values= getValuesFromOptions(options); KeyValuePair response = await httpPost(url, values); return 0; } public static async Task<KeyValuePair> httpPost(string url, List<KeyValuePair> parameters) { var httpClient = new HttpClient(new HttpClientHandler()); HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)); int code = (int)response.StatusCode; response.EnsureSuccessStatusCode(); string responseString = await response.Content.ReadAsStringAsync(); return new KeyValuePair(code, responseString); }
Позвольте мне показать вам нерабочий пример:
private int dispatch(string options) { int res = authorize(options).Result; return res; } static private int authorize(string options) { string values= getValuesFromOptions(options); Task<KeyValuePair> response = httpPost(url, values); doSomethingWith(response.Result); // execution will hang here forever return 0; } public static async Task<KeyValuePair> httpPost(string url, List<KeyValuePair> parameters) { var httpClient = new HttpClient(new HttpClientHandler()); HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)); int code = (int)response.StatusCode; response.EnsureSuccessStatusCode(); string responseString = await response.Content.ReadAsStringAsync(); return new KeyValuePair(code, responseString); }
Я также попытался использовать все 3 метода не async и заменить await
в httpPost
на .Result
s, но затем он будет вечно вешать в строке HttpResponseMessage response = httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)).Result;
Может ли кто-нибудь просветить меня и объяснить, что моя ошибка?
У вас есть SynchronizationContext
, и этот контекст захватывается, когда вы await
так что продолжения (ы) могут выполняться в этом контексте.
Вы запускаете задачу async, планируя продолжение, которое будет выполняться в вашем основном контексте в какой-то более поздний момент.
Затем, прежде чем операция async будет завершена, у вас есть код в вашем основном контексте, который выполняет блокировку ожидания операции async. Продолжение невозможно запустить, потому что контекст занят, ожидая продолжения. Классический тупик.
Вот почему важно «асинхронно все», как это было в первом примере.
Есть несколько хаков, которые могут работать в тупике во втором примере, но это все еще не то, что вы должны делать. Весь asynchronous ход – избегать блокировки ваших streamов. Если вы просто продолжаете блокировать ожидание задачи, вы проиграете цель перехода асинхронно. Либо сделайте все асинхронным, либо ничего асинхронным, если у вас нет выбора.