使用等待Task()时IIS失败

时间:2013-06-19 22:56:11

标签: c# multithreading wcf asp.net-web-api async-await

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

5 个答案:

答案 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)

@Panagiotis Kanavos的回答让它发挥作用。这是一个清晰的摘要,说明如何使用Web API为那些Google员工在那里使用IIS工作

到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();

}