0

我需要从不同的 url 下载一些文本,然后我使用 CountDownEvent 来处理我的事件 Donwnload 完成的次数,但问题是我的 CountDownEvent 永远不会设置为零,这仍在等待。

知道这段代码有什么问题吗?

namespace WebApplication.AsyncCall
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Threading;

    public partial class _Default : System.Web.UI.Page
    {
        private CountdownEvent countDown = null;
        public CountdownEvent CountDown
        {
            get
            {
                if (this.countDown == null)
                {
                    this.countDown = new CountdownEvent(1);
                }

                return this.countDown;
            }
        }

        private List<string> text = null;
        public List<string> Text
        {
            get
            {
                if (this.text == null)
                {
                    this.text = new List<string>();
                }

                return this.text;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            List<string> rssSources = new List<string>();

            rssSources.Add(@"http://news.yahoo.com/rss/entertainment");
            rssSources.Add(@"http://go.microsoft.com/fwlink/?linkid=84795&clcid=409");

            foreach (string uri in rssSources)
            {
                this.CountDown.AddCount();
                LoadSources(uri);
            }

            this.CountDown.Signal();
            this.CountDown.Wait();
        }

        private void LoadSources(string uri)
        {
            WebClient client = new WebClient();
            client.DownloadStringAsync(new Uri(uri, UriKind.Absolute));

            client.DownloadStringCompleted += (s, a) =>
            {
                if (a.Error == null && !a.Cancelled)
                {
                    this.Text.Add(a.Result);
                    this.CountDown.Signal();
                }
            };
        }
    }
}
4

1 回答 1

0

我终于弄清楚如何解决我的问题,问题是尽管我正在异步触发我的下载事件,但它们似乎仍然在主线程上执行,这意味着this.CountDown.Wait()在任何下载完成之前调用它然后我this.CountDown没有因此,signaledthis.CountDown永远不会设置为零,这仍然在等待。

这是我所做的:

进入foreach我用 ThreadPool.QueueUserWorkItem 替换了对该方法的调用,LoadSources(uri)它将一个方法排队等待执行。该方法在线程池线程可用时执行。

ThreadPool.QueueUserWorkItem(new WaitCallback(LoadSources), (object)uri);

我还必须更改 LoadSources 方法以适应我的调整。

private void LoadSources(object uri)
{
    WebClient client = new WebClient();
    client.DownloadStringAsync(new Uri(uri.ToString(), UriKind.Absolute));

    client.DownloadStringCompleted += (s, a) =>
    {
        lock (thisLock)
        {
            try
            {
                if (a.Error == null && !a.Cancelled)
                {
                    this.Text.Add(a.Result);
                }
            }
            finally
            {
                this.CountDown.Signal();
            } 
        }
    };
}

如您所见,我添加了一个锁定语句以避免两个或多个线程尝试this.Text.Add同时调用

在此之前,我只是声明了一个要锁定的私有对象。

private Object thisLock = new Object();
于 2012-11-28T20:11:36.813 回答