当你有服务器端代码(即一些ApiController)并且你的函数是异步的 - 所以它们返回Task<SomeObject>- 你认为最好的做法是等待你调用的函数ConfigureAwait(false)吗?
我已经读过它更高效,因为它不必将线程上下文切换回原始线程上下文.但是,使用ASP.NET Web Api,如果您的请求是在一个线程上进行的,并且等待某些函数和调用ConfigureAwait(false),则可能会在返回ApiController函数的最终结果时将您置于不同的线程上.
我在下面输入了一个我正在谈论的例子:
public class CustomerController : ApiController
{
public async Task<Customer> Get(int id)
{
// you are on a particular thread here
var customer = await SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);
// now you are on a different thread! will that cause problems?
return customer;
}
}
Run Code Online (Sandbox Code Playgroud) 请考虑以下代码,其中BaseAddress定义了部分URI路径.
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://something.com/api");
var response = await client.GetAsync("/resource/7");
}
Run Code Online (Sandbox Code Playgroud)
我希望这可以执行GET请求http://something.com/api/resource/7.但事实并非如此.
经过一番搜索,我发现这个问题和答案:HttpClient with BaseAddress.建议是/放在最后BaseAddress.
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://something.com/api/");
var response = await client.GetAsync("/resource/7");
}
Run Code Online (Sandbox Code Playgroud)
它仍然无法正常工作.这是文档:HttpClient.BaseAddress这里发生了什么?
我发现了一些使用c#async/ awaitkeywords的异步编程的最佳实践(我是c#5.0的新手).
给出的建议之一是:
稳定性:了解同步上下文
...某些同步上下文是不可重入和单线程的.这意味着在给定时间内只能在上下文中执行一个工作单元.一个例子是Windows UI线程或ASP.NET请求上下文.在这些单线程同步上下文中,很容易使自己陷入僵局.如果从单线程上下文中生成任务,然后在上下文中等待该任务,则等待代码可能会阻止后台任务.
public ActionResult ActionAsync()
{
// DEADLOCK: this blocks on the async task
var data = GetDataAsync().Result;
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
Run Code Online (Sandbox Code Playgroud)
如果我自己尝试剖析它,主线程会产生一个新线程MyWebService.GetDataAsync();,但由于主线程在那里等待,它等待结果GetDataAsync().Result.同时,说数据准备好了.为什么主线程不继续它的延续逻辑并从中返回字符串结果GetDataAsync()?
有人可以解释一下为什么上面的例子中存在死锁吗?我完全不知道问题是什么......