C# 使用异步&;等待
我希望我的程序遵循以下调用堆栈/工作流:C# 使用异步&;等待,c#,.net,http,async-await,C#,.net,Http,Async Await,我希望我的程序遵循以下调用堆栈/工作流: dispatch() authorize() httpPost() 我的想法是httpPost()将是异步的,而其他两个方法保持非异步。然而,出于某种原因,除非我使2和3异步,否则它将无法工作。也许我还有些误会 据我所知,我可以: 调用异步方法时使用wait关键字(这将挂起该方法并在异步方法完成后继续),或者 省略wait关键字,改为调用异步方法返回值的Task.Result,该值将被阻塞,直到结果可用为止 以下是工作示例: private int d
dispatch()
authorize()
httpPost()
httpPost()
将是异步的,而其他两个方法保持非异步。然而,出于某种原因,除非我使2和3异步,否则它将无法工作。也许我还有些误会
据我所知,我可以:
wait
关键字(这将挂起该方法并在异步方法完成后继续),或者wait
关键字,改为调用异步方法返回值的Task.Result
,该值将被阻塞,直到结果可用为止以下是工作示例:
private int dispatch(string options)
{
int res = authorize(options).Result;
return res;
}
static async private Task<int> authorize(string options)
{
string values = getValuesFromOptions(options);
KeyValuePair<int, string> response = await httpPost(url, values);
return 0;
}
public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> 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<int, string>(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<int, string>> response = httpPost(url, values);
doSomethingWith(response.Result); // execution will hang here forever
return 0;
}
public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> 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<int, string>(code, responseString);
}
private int dispatch(字符串选项)
{
int res=授权(选项)。结果;
返回res;
}
静态异步专用任务授权(字符串选项)
{
字符串值=getValuesFromOptions(选项);
KeyValuePair响应=等待httpPost(url,值);
返回0;
}
公共静态异步任务httpPost(字符串url,列表参数)
{
var httpClient=newhttpclient(newhttpclienthandler());
HttpResponseMessage response=等待httpClient.PostAsync(url,新表单UrlEncodedContent(参数));
int code=(int)response.StatusCode;
response.EnsureSuccessStatusCode();
string responseString=wait response.Content.ReadAsStringAsync();
返回新的KeyValuePair(代码、responseString);
}
以下是非工作示例:
private int dispatch(string options)
{
int res = authorize(options).Result;
return res;
}
static async private Task<int> authorize(string options)
{
string values = getValuesFromOptions(options);
KeyValuePair<int, string> response = await httpPost(url, values);
return 0;
}
public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> 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<int, string>(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<int, string>> response = httpPost(url, values);
doSomethingWith(response.Result); // execution will hang here forever
return 0;
}
public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> 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<int, string>(code, responseString);
}
private int dispatch(字符串选项)
{
int res=授权(选项)。结果;
返回res;
}
静态私有整数授权(字符串选项)
{
字符串值=getValuesFromOptions(选项);
任务响应=httpPost(url,值);
doSomethingWith(response.Result);//执行将永远挂在这里
返回0;
}
公共静态异步任务httpPost(字符串url,列表参数)
{
var httpClient=newhttpclient(newhttpclienthandler());
HttpResponseMessage response=等待httpClient.PostAsync(url,新表单UrlEncodedContent(参数));
int code=(int)response.StatusCode;
response.EnsureSuccessStatusCode();
string responseString=wait response.Content.ReadAsStringAsync();
返回新的KeyValuePair(代码、responseString);
}
我还尝试让所有3种方法都是非异步的,将httpPost
中的wait
s替换为.Result
s,但是它永远挂在httpresponsemessageresponse=httpClient.postsync(url,新FormUrlEncodedContent(参数)).Result代码>
有人能告诉我并解释我的错误是什么吗?您有一个同步上下文
,当您等待时会捕获该上下文,以便继续可以在该上下文中运行
您正在启动一个异步任务,安排一个continuation在稍后的某个时间在主上下文中运行
然后,在异步操作完成之前,主上下文中的代码会对异步操作执行阻塞等待。无法计划继续运行,因为上下文正忙于等待继续。经典的死锁
这就是为什么“一路异步”很重要的原因,正如您在第一个示例中所做的那样
在第二个示例中,有一些黑客可以绕过死锁,但这仍然不是您应该做的事情。异步化的关键是避免阻塞线程。如果您只是在任务上执行阻塞等待,那么您就无法达到异步的目的。除非您别无选择,否则将所有内容都设置为异步,或者不设置任何内容为异步。要测试这是否是正确的解释,请使用非工作代码并将每个“wait X”更改为“wait X.configurewait(false)”。如果解释是正确的,它现在应该可以工作了。另一个注意事项:如果您在ASP.Net或UI应用程序中运行,则会有一个SynchronizationContext。如果是这样,请比较在独立控制台项目中运行相同的代码。@servy:但是,我没有得到的是我的工作示例和非工作示例之间的实际区别。我明白你说的await
在时安排一个延续。Result
只是简单的块(是这样吗?),但这是否意味着我需要一个无休止的异步等待链,因为没有await
我会阻塞/死锁我的线程?我的意思是第一个例子没有在int res=authorize(options)中阻塞代码>,但第二个示例在doSomethingWith(response.Result)中阻塞代码>,为什么?