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,事件的声明由于{}而发出错误警报