C# 在我最初的设计中,我是这样做的,但我不太确定如何实现它。另一方面,有些下载可能需要一段时间,是否有方法将进度报告回GUI线程。这是我喜欢连续执行DownloadDataASync()的原因之一,因为我可以订阅DownloadProgressChanged事
C# 在我最初的设计中,我是这样做的,但我不太确定如何实现它。另一方面,有些下载可能需要一段时间,是否有方法将进度报告回GUI线程。这是我喜欢连续执行DownloadDataASync()的原因之一,因为我可以订阅DownloadProgressChanged事,c#,c#-4.0,thread-safety,C#,C# 4.0,Thread Safety,在我最初的设计中,我是这样做的,但我不太确定如何实现它。另一方面,有些下载可能需要一段时间,是否有方法将进度报告回GUI线程。这是我喜欢连续执行DownloadDataASync()的原因之一,因为我可以订阅DownloadProgressChanged事件。这不是一个关键的要求,只是很高兴知道这是否可能。谢谢你的解决方案。这并不是我在问题中所要求的,但答案让我重新思考设计,使之与线程安全无关。谢谢你的回答。我认为这个答案确实回答了我的问题,但我选择了sixlettervariables,因为他
在我最初的设计中,我是这样做的,但我不太确定如何实现它。另一方面,有些下载可能需要一段时间,是否有方法将进度报告回GUI线程。这是我喜欢连续执行
DownloadDataASync()
的原因之一,因为我可以订阅DownloadProgressChanged
事件。这不是一个关键的要求,只是很高兴知道这是否可能。谢谢你的解决方案。这并不是我在问题中所要求的,但答案让我重新思考设计,使之与线程安全无关。谢谢你的回答。我认为这个答案确实回答了我的问题,但我选择了sixlettervariables,因为他的开箱即用解决方案帮助改进了我的设计,所以我几乎不必担心线程安全。我试着给你几张赞成票。
private WebClient webClient = new WebClient();
private Queue<Uri> requestQueue = new Queue<Uri>();
public Boolean DownloadNextASync()
{
if (webClient.IsBusy)
return false;
if (requestQueue.Count == 0)
return false
var uri = requestQueue.Dequeue();
webClient.DownloadDataASync(uri);
return true;
}
var queue = new BlockingCollection<Uri>();
var maxClients = 4;
// Optionally provide another producer/consumer collection for the data
// var data = new BlockingCollection<Tuple<Uri,byte[]>>();
// Optionally implement CancellationTokenSource
var clients = from id in Enumerable.Range(0, maxClients)
select Task.Factory.StartNew(
() =>
{
var client = new WebClient();
while (!queue.IsCompleted)
{
Uri uri;
if (queue.TryTake(out uri))
{
byte[] datum = client.DownloadData(uri); // already "async"
// Optionally pass datum along to the other collection
// or work on it here
}
else Thread.SpinWait(100);
}
});
// Add URI's to search
// queue.Add(...);
// Notify our clients that we've added all the URI's
queue.CompleteAdding();
// Wait for all of our clients to finish
clients.WaitAll();
public static Task<byte[]> DownloadAsync(Uri uri, Action<double> progress)
{
var source = new TaskCompletionSource<byte[]>();
Task.Factory.StartNew(
() =>
{
var client = new WebClient();
client.DownloadProgressChanged
+= (sender, e) => progress(e.ProgressPercentage);
client.DownloadDataCompleted
+= (sender, e) =>
{
if (!e.Cancelled)
{
if (e.Error == null)
{
source.SetResult((byte[])e.Result);
}
else
{
source.SetException(e.Error);
}
}
else
{
source.SetCanceled();
}
};
});
return source.Task;
}
// var urls = new List<Uri>(...);
// var progressBar = new ProgressBar();
Task.Factory.StartNew(
() =>
{
foreach (var uri in urls)
{
var task = DownloadAsync(
uri,
p =>
progressBar.Invoke(
new MethodInvoker(
delegate { progressBar.Value = (int)(100 * p); }))
);
// Will Block!
// data = task.Result;
}
});
1. var valueToDequeue = this._internalList[this._startPointer];
2. this._startPointer = (this._startPointer + 1) % this._internalList.Count;
3. return valueToDequeue;
private readonly object _lock = new object();
...
lock (this._lock) {
// body of method
}