【发布时间】:2016-11-24 08:36:50
【问题描述】:
我设置了一堆Console.WriteLines,据我所知,当我在 .NET Fiddle 中运行以下命令时,它们都没有被调用。
using System;
using System.Net;
using System.Linq.Expressions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Collections.Generic;
public class Program
{
private static readonly object locker = new object();
private static readonly string pageFormat = "http://www.letsrun.com/forum/forum.php?board=1&page={0}";
public static void Main()
{
var client = new WebClient();
// Queue up the requests we are going to make
var tasks = new Queue<Task<string>>(
Enumerable
.Repeat(0,50)
.Select(i => new Task<string>(() => client.DownloadString(string.Format(pageFormat,i))))
);
// Create set of 5 tasks which will be the at most 5
// requests we wait on
var runningTasks = new HashSet<Task<string>>();
for(int i = 0; i < 5; ++i)
{
runningTasks.Add(tasks.Dequeue());
}
var timer = new System.Timers.Timer
{
AutoReset = true,
Interval = 2000
};
// On each tick, go through the tasks that are supposed
// to have started running and if they have completed
// without error then store their result and run the
// next queued task if there is one. When we run out of
// any more tasks to run or wait for, stop the ticks.
timer.Elapsed += delegate
{
lock(locker)
{
foreach(var task in runningTasks)
{
if(task.IsCompleted)
{
if(!task.IsFaulted)
{
Console.WriteLine("Got a document: {0}",
task.Result.Substring(Math.Min(30, task.Result.Length)));
runningTasks.Remove(task);
if(tasks.Any())
{
runningTasks.Add(tasks.Dequeue());
}
}
else
{
Console.WriteLine("Uh-oh, task faulted, apparently");
}
}
else if(!task.Status.Equals(TaskStatus.Running)) // task not started
{
Console.WriteLine("About to start a task.");
task.Start();
}
else
{
Console.WriteLine("Apparently a task is running.");
}
}
if(!runningTasks.Any())
{
timer.Stop();
}
}
};
}
}
我也很感激有关如何简化或修复其中的任何错误逻辑的建议。我想要做的模式就像
(1) 创建一个包含 N 个任务的队列
(2)创建一组M个任务,前M个出列项来自(1)
(3)启动M个任务运行
(4) X 秒后,检查已完成的任务。
(5) 对于任何已完成的任务,对结果执行某些操作,从集合中移除该任务并用队列中的另一个任务替换它(如果队列中还有其他任务)。
(6) 无限期地重复 (4)-(5)。
(7) 如果集合中没有剩余任务,我们就完成了。
但也许有更好的方法来实现它,或者也许有一些 .NET 函数可以轻松封装我正在尝试做的事情(以指定的最大并行度并行的 Web 请求)。
【问题讨论】:
-
您选择这种方法而不是仅仅将任务推入线程池有什么原因吗?不是说你这样做是错的,我只是好奇。
-
带有特定 DOP 的简单 ActionBlock
可以解决问题
标签: c# .net multithreading asynchronous parallel-processing