我有一个WebAPI ASP.NET解决方案。我已将web.config设置为:
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
在通话中,我需要获得3个任务的结果(每个10秒):
Task<Cat> catAsync = GetCatAsync();
Task<Dog> dogAsync = GetDogAsync();
Task<Pig> pigAsync = GetPigAsync();
await Task.WhenAll(catAsync , dogAsync , pigAsync );
cat= catAsync.Result;
dog= dogAsync.Result;
pig= pigAsync.Result;
我可以调用一次,但后来对此的调用似乎只是死在一个线程中,Cat和Dog可能会运行,但Pig似乎在蒸发。大约一分钟后,这些开始出现:
The thread '<No Name>' (0x2f60) has exited with code 0 (0x0).
The thread '<No Name>' (0x974) has exited with code 0 (0x0).
The thread '<No Name>' (0x1ea8) has exited with code 0 (0x0).
我的任务看起来像这样:
private async Task<Cat> CatAsync()
{
await Task.Run(() =>
{
//Use WCF to get some data from a service
});
return cat;
}
运行IISRESET让我再次运行该网站。
* 编辑
我在阅读Panagiotis Kanavos的答案之后发布了下面的解决方案,该解决方案适用于此示例
答案 0 :(得分:3)
其他人建议的问题是同步上下文。等待在等待开始等待的同步上下文(本质上是线程)中继续执行。如果该线程已被阻止,例如。通过等待其他东西,代码死锁。
为避免这种情况,您应该通过调用await
跟随对ConfigureAwait(false)
的任何调用,以使运行时继续在另一个线程中。
以下代码将顺利运行。删除任何ConfigureAwait调用都会导致死锁。
此外,只要您使用xxxAsync方法,就不需要在Task.Run中进行WCF调用。这使代码更加清晰
最后,如果您只想等待完成,则应使用Task.WaitAll()而不是等待Task.WhenAll()。 Task.WaitAll()不会破坏syncrhonization上下文,因此您不需要再添加另一个ConfigureAwait()
protected void Page_Load(object sender, EventArgs e)
{
var results = GetThem().Result;
}
private async Task<Tuple<Cat,Dog,Pig>> GetThem()
{
Task<Cat> catAsync = GetCatAsync();
Task<Dog> dogAsync = GetDogAsync();
Task<Pig> pigAsync = GetPigAsync();
await Task.WhenAll(catAsync, dogAsync, pigAsync).ConfigureAwait(false);
//better yet,
// Task.WaitAll(catAsync, dogAsync, pigAsync);
var cat = catAsync.Result;
var dog = dogAsync.Result;
var pig = pigAsync.Result;
return Tuple.Create(cat, dog, pig);
}
private async Task<Pig> GetPigAsync()
{
var cat = new Pig();
var res = await GetGoogleSearchHTML("cat").ConfigureAwait(false);
using (StreamReader sr = new StreamReader(res.GetResponseStream()))
{
cat.Name = await sr.ReadToEndAsync().ConfigureAwait(false);
}
return cat;
}
public async Task<WebResponse> GetGoogleSearchHTML(string type)
{
System.Net.WebRequest request = System.Net.HttpWebRequest.Create(String.Format("http://www.google.com/search?noj=1&site=cat&source=hp&q={0}&oq=search", type));
System.Net.WebResponse response = await request.GetResponseAsync().ConfigureAwait(false);
return response;
}
答案 1 :(得分:1)
到Web.Config add
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
然后创建任务并使用WaitAll()
Task<Cat> cat= GetCat();
Task<Dog> dog= GetDog();
Task.WaitAll(cat,dog,pig etc);
NowUseTheValues(cat.Result,dog.Result);
任务应该是没有异步的普通任务:
private Task<Cat> GetCat()
{
return Task.Run(() => {
return new Cat();
});
}
答案 2 :(得分:0)
如果您的操作长时间运行,IIS可以终止所有线程并终止请求。可以在web.config
中设置代码执行超时答案 3 :(得分:0)
尝试从函数中删除async-await:
private Task<Cat> CatAsync()
{
return Task.Run(() =>
{
//Use WCF to get some data from a service
});
}
您可以在外部函数中保持等待。请检查以获得解释:Why does this async action hang?
答案 4 :(得分:-1)
玉米,
我使用你的代码,(使用WebRequest和Web响应 - 在你的WCF调用中同步)
只要我做了一个WebResponse / Requests Async(你将在那里进行WCF调用),它就会挂起。
private async Task<Cat> GetCatAsync()
{
Cat cat = new Cat(); ;
await Task.Run(() =>
{
//Use WCF to get some data from a service
var res = GetGoogleSearchHTML("cat").Result;
using (StreamReader sr = new StreamReader(res.GetResponseStream()))
{
cat.catName = sr.ReadToEnd();
}
});
return cat;
}
public async Task<WebResponse> GetGoogleSearchHTML(string type)
{
System.Net.WebRequest request = System.Net.HttpWebRequest.Create(String.Format("http://www.google.com/search?noj=1&site=cat&source=hp&q={0}&oq=search",type));
System.Net.WebResponse response = await request.GetResponseAsync();
return response;
}
public class Dog {
public string dogName { get; set; }
}
public class Pig
{
public string pigName { get; set; }
}
public class Cat
{
public string catName { get; set; }
}
private async Task<Dog> GetDogAsync()
{
Dog dog = new Dog();
await Task.Run(() =>
{
WebResponse res = GetGoogleSearchHTML("dog").Result;
using (StreamReader sr = new StreamReader(res.GetResponseStream()))
{
dog.dogName = sr.ReadToEnd();
}
//Use WCF to get some data from a service
});
return dog;
}
private async Task<Pig> GetPigAsync()
{
Pig pig = new Pig(); ;
await Task.Run(() =>
{
var res = GetGoogleSearchHTML("pig").Result;
using(StreamReader sr = new StreamReader(res.GetResponseStream()))
{
pig.pigName = sr.ReadToEnd();
}
//Use WCF to get some data from a service
});
return pig;
}
public async void GetTypes()
{
List<Task> taskList = new List<Task>() { };
Task<Cat> catAsync = GetCatAsync();
Task<Dog> dogAsync = GetDogAsync();
Task<Pig> pigAsync = GetPigAsync();
await Task.WhenAll(catAsync , dogAsync , pigAsync );
var cat= catAsync.Result;
var dog= dogAsync.Result;
var pig= pigAsync.Result;
}
public WebApiResult GetResponses()
{
GetTypes();
return new WebApiResult();
}