首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >任务陷入"WaitingForActivation“的状态

任务陷入"WaitingForActivation“的状态
EN

Stack Overflow用户
提问于 2014-03-04 07:19:46
回答 2查看 3.2K关注 0票数 2

这与.NET 4.0有关

我正在尝试使用Task异步地从多个WebAPI中获取数据。在控制台应用程序中,程序运行得很好,但是当我创建web应用程序时,任务的状态总是停留在"WaitingForActivation“上。任何帮助都将不胜感激。以下是我的代码:

代码语言:javascript
复制
    public String[] CallClientAPI(string[] addresses)
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        int timeToWait = 3000; //wait for 3 seconds to fetch API Data

        Task.Factory.StartNew(() =>
        {
            Thread.Sleep(timeToWait);
            cts.Cancel();
        });

        Task<String[]> webTask = GetAPIData(addresses, cts.Token);
        //webTask is always in "WaitingForActivation" mode only ..

        if (!webTask.IsCompleted)
        {
            Thread.SpinWait(5000000);
        }

        String[] results = null;

        try
        {
            results = webTask.Result;
        }
        catch
        {               
        }
        //other code
    }

编辑:

代码语言:javascript
复制
    public Task<string[]> GetAPIData(String[] urls, CancellationToken token)
    {
        TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();
        WebClient[] webClients = new WebClient[urls.Length];

        token.Register(() =>
            {
                foreach (var wc in webClients)
                {
                    if (wc != null)
                        wc.CancelAsync();
                }                    
            });

        object m_lock = new object();
        int count = 0;
        List<string> results = new List<string>();
        for (int i = 0; i < urls.Length; i++)
        {
            webClients[i] = new WebClient();

            webClients[i].DownloadStringCompleted += (obj, args) =>
                {
                    if (args.Cancelled == true)
                    {
                        tcs.TrySetCanceled();
                        return;
                    }
                    else if (args.Error != null)
                    {
                        tcs.TrySetException(args.Error);
                        return;
                    }
                    else
                    {
                        results.Add(args.Result);
                    }

                    lock (m_lock)
                    {
                        count++;
                        if (count == urls.Length)
                        {
                            tcs.TrySetResult(results.ToArray());
                        }
                    }
                };

            Uri address = null;
            try
            {
                address = new Uri(urls[i]);
                webClients[i].DownloadStringAsync(address, address);
            }

            catch (UriFormatException ex)
            {
                tcs.TrySetException(ex);
                return tcs.Task;
            }
        }

        return tcs.Task;
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-03-13 05:25:01

这正是我们所期望的。简单又简单!!

代码语言:javascript
复制
    public String[] CallClientAPI(string[] addresses)
    {
        int timeToWait = Int32.Parse(ConfigurationManager.AppSettings["API_QUERY_TIMEOUT"].ToString());
        CancellationTokenSource cts = new CancellationTokenSource();

        Task.Factory.StartNew(() =>
            {
                Thread.Sleep(timeToWait);
                cts.Cancel();
            });

        ParallelOptions po = new ParallelOptions();
        po.CancellationToken = cts.Token;

        try
        {
            Parallel.ForEach(addresses, po, (address) =>
                {
                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
                        request.Method = "GET";
                        request.ContentType = "text/xml";
                        request.Timeout = timeToWait;

                        WebResponse response = request.GetResponse();

                        Stream respstream = response.GetResponseStream();
                        Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
                        StreamReader sr = new StreamReader(respstream, encode);

                        myresult.Add(sr.ReadToEnd());
                    }
                    catch
                    {
                    }
                });
        }
        catch
        {
        }

        return myresult.ToArray();
    }
票数 0
EN

Stack Overflow用户

发布于 2014-03-10 19:03:00

看起来您正在UI线程上开始下载。问题在于,Completed处理程序试图在UI线程上执行。但这是不可能的,因为UI线程在调用Result时被阻塞。其结果是您有一个死锁。

正确的解决方案是不阻止UI线程。这在C# 5.0中尤其有效(假设您使用的是VS 2012,可以与.Net 4.0一起使用),但在C# 4.0中也可以使用ContinueWith()之类的东西。

如果您真的想在处理下载时阻止UI线程(我真的不建议这样做),那么在一个单独的线程上执行所有的WebClient代码(使用Task.Factory.StartNew())。这样,Completed处理程序就不会试图在UI线程上恢复,从而解决死锁。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22165388

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档