C# WebClient异步卡滞

C# WebClient异步卡滞,c#,asynchronous,webclient,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://ww

我有以下代码:

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

当我在一个按钮点击事件中运行这段代码时,它工作得很好。但是,当我从big类运行代码时,它会被阻塞,无法到达func:clien_DownloadDataCompleted。

您的做法完全错误。如果你想下载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));
}

为什么在等待完成时使用异步版本?回调如何访问autoResetEvent?@jgauffin,我使用async,因为它是最快的。我更新我的codeAsync并没有明显比同步方法快或慢。IO是瓶颈。你的代码不是线程安全的,有点讽刺;因为在方法中使用sync DownloadString将使其线程安全。正如@CodeCaster所说:性能不会有任何提高,因为与服务器对话所需的时间是实际方法调用的几倍。这是早熟优化的一个主要例子,它也会产生可读性较差的代码。@Chanipoz我从搜索为什么使用异步方法时找到的结果中偷取了一个定义:同步方法调用在继续程序流之前等待方法完成,而异步方法调用将立即返回,以便在被调用方法完成其工作时,程序可以执行其他操作。@jgauffin,您写道:downloader.Completed没有名为Completed的func代码中有错误。我只是直接把它打在答题箱里。给你一个完全有效的代码只会让你在不理解它的情况下使用它。研究代码,您将看到事件的名称。@jgauffin,谢谢,但尽管我研究了代码,并将其更改为与我匹配,但我不理解所有代码,也不理解它是什么事件。下载程序中只声明了两个事件。你有50%的时间做对;提示:事件在declaration@jgauffin,事件的声明由于{}而发出错误警报