WebClient异步卡住了

时间:2012-10-10 10:42:17

标签: c# asynchronous webclient

我有这段代码:

autoResetEvent = new AutoResetEvent(false);
clien = new WebClient();
clien.Encoding = Encoding.UTF8;
clien.DownloadDataCompleted += new DownloadDataCompletedEventHandler(clien_DownloadDataCompleted);
clien.DownloadDataAsync(new Uri("http://www.classoneequipment.com/"));
autoResetEvent.WaitOne();

void clien_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
 {
        Encoding enc = Encoding.UTF8;
        myString = enc.GetString(e.Result);
        autoResetEvent.Set();
 }

当我在按钮点击事件中运行此代码时 - 它工作正常。但是当我从大类运行代码时,它会被卡住并且不会到达func:clien_DownloadDataCompleted。

1 个答案:

答案 0 :(得分:3)

你接近这一切都错了。如果你想下载3000或更多的页面,你必须更有效率,而不是等待每次下载的事件。

实施(只是草稿,你必须完成它)

public class Downloader
{
    ConcurrentQueue<Uri> _queue = new ConcurrentQueue<Uri>();
    int _maxWorkers = 10;
    long _currentWorkers = 0;
    ManualResetEvent _completed;

    public void Enqueue(Uri uri)
    {
        _queue.Enqueue(uri);
        if (Interlocked.Read(_currentWorkers)  < _maxWorkers)
        {
            // not very thread safe, but we just want to limit the workers
            // within a reasonable limit. 1 or 2 more doesn't really matter.
            Interlocked.Increment(_currentWorkers);

            // yes, i'm a bit old fashioned.
            TriggerJob();
        }
    }

    private void TriggerJob()
    {
        Uri uri;
        if (!_queue.TryDequeue(out uri))
        {
            Interlocked.Decrement(_currentWorkers);
            return;
        }

        var client = new WebClient();
        client.Encoding = Encoding.UTF8;
        client.DownloadDataCompleted += DownloadDataCompleted;
        client.DownloadDataAsync(uri);
    }

    private void DownloadDataCallback(object sender, DownloadDataCompletedEventArgs e)
    {
        try
        {
            // If the request was not canceled and did not throw 
            // an exception, display the resource. 
            if (!e.Cancelled && e.Error == null)
            {
                var args = new DownloadedEventArgs { uri = e.Uri, data = (byte[])e.result};
                DownloadCompleted(this, args)
            }
            else
            {
                var args = new DownloadFailedEventArgs { uri = e.Uri, error = e.Error };
                DownloadFailed(this, args);
            }
        }
        catch (Exception err)
        {
            var args = new DownloadFailedEventArgs { uri = e.Uri, error = err };
            DownloadFailed(this, args);
        }

        TriggerJob();
    }

    public event EventHandler<DownloadedEventArgs> DownloadCompleted = delegate{};
    public event EventHandler<DownloadFailedEventArgs> DownloadFailed = delegate{};

}


public class DownloadedEventArgs
{
    public Uri uri;
    public byte[] data;
}

public class DownloadFailedEventArgs
{
    public Uri uri;
    public Exception error;
}

用法:

var downloader = new Downloader();
downloader.Completed += (o,e) { Console.WriteLine("Whoohoho, completed: " + e.Uri); };

for (x = 1; x < 100000; x++)
{
    downloader.Enqueue(new Uri("http://somewhere.com));
}