1

我有一个 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 and 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 的答案后,我在下面发布了适用于此示例的解决方案

4

5 回答 5

4

其他人建议的问题是同步上下文。Await 在开始等待的同步上下文(本质上是线程)中恢复执行。如果该线程已经被阻塞,例如。通过在其他事情上等待自己,代码会死锁。

为避免这种情况,您应该在任何调用之后await调用ConfigureAwait(false)以使运行时在不同的线程中继续。

以下代码将顺利运行。但是,删除任何 ConfigureAwait 调用都会导致死锁。

此外,您无需在 Task.Run 中进行 WCF 调用,只要您使用 xxxAsync 方法即可。这也使代码更清晰

最后,如果您只想等待完成,您应该使用 Task.WaitAll() 而不是 await Task.WhenAll()。Task.WaitAll() 不会与同步上下文混淆,因此您无需添加另一个 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;
    }
于 2013-06-20T11:59:55.597 回答
1

@Panagiotis Kanavos 的回答让它起作用了。这是我如何使用 Web API 让任务在 IIS 中为那些 Google 员工工作的清晰摘要

到 Web.Config 添加

<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();
       });
 }
于 2013-06-20T16:15:54.680 回答
0

尝试从您的函数中删除 async-await:

private Task<Cat> CatAsync()
{
    return Task.Run(() =>
        {
           //Use WCF to get some data from a service
        });
}

您可以将 await 保留在外部函数中。检查这个以获得解释:为什么这个异步操作会挂起?

于 2013-06-19T23:17:57.310 回答
0

如果您的操作长时间运行,IIS 可以终止所有线程并终止请求。代码执行超时可以在 web.config 中设置

于 2013-06-19T23:03:45.520 回答
-1

com,

我让它与您的代码一起使用,(使用 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();

}
于 2013-06-20T01:02:32.517 回答