关于使用并行web获取任务队列代码的问题
本文关键字:代码 问题 任务队列 获取 于使用 并行 web | 更新日期: 2023-09-27 18:05:35
因此,我得到了这段代码,以便从REST api向下钻取XML文档的层次结构。我早些时候发布了关于如何使它递归的建议,然后我继续使它并行。
首先,我对它的运行速度感到震惊——它在不到12秒的时间内取出了318个XML文档,相比之下,单线程需要10多分钟——我真的没有想到会有这么快的收获。这其中是否有什么隐情,因为它看起来好得令人难以置信?
第二,我怀疑这段代码是在实现一个通用模式,但可能是以一种非"惯用"的方式。我有一种"生产者-消费者队列",有两个单独的锁定对象。有更标准的方法吗?
代码。
public class ResourceGetter
{
public ResourceGetter(ILogger logger, string url)
{
this.logger = logger;
this.rootURL = url;
}
public List<XDocument> GetResources()
{
GetResources(rootURL);
while (NumTasks() > 0) RemoveTask().Wait();
return resources;
}
void GetResources(string url)
{
logger.Log("Getting resources at " + url);
AddTask(Task.Factory.StartNew(new Action(() =>
{
var doc = XDocument.Parse(GetXml(url));
if (deserializer.CanDeserialize(doc.CreateReader()))
{
var rl = (resourceList)deserializer.Deserialize(doc.CreateReader());
foreach (var item in rl.resourceURL)
{
GetResources(url + item.location);
}
}
else
{
logger.Log("Got resource for " + url);
AddResrouce(doc);
}
})));
}
object resourceLock = new object();
List<XDocument> resources = new List<XDocument>();
void AddResrouce(XDocument doc)
{
lock (resourceLock)
{
logger.Log("add resource");
resources.Add(doc);
}
}
object taskLock = new object();
Queue<Task> tasks = new Queue<Task>();
void AddTask(Task task)
{
lock (taskLock)
{
tasks.Enqueue(task);
}
}
Task RemoveTask()
{
lock (taskLock)
{
return tasks.Dequeue();
}
}
int NumTasks()
{
lock (taskLock)
{
logger.Log(tasks.Count + " tasks left");
return tasks.Count;
}
}
ILogger logger;
XmlSerializer deserializer = new XmlSerializer(typeof(resourceList));
readonly string rootURL;
}
顺便说一下,我不会为管理任务列表、所有锁和NumTasks()方法的代码而烦恼。使用CountdownEvent会更简单,因为它一开始就是线程安全的。只要在创建新任务时增加它,在任务完成时减少它,就像你现在所做的那样,但没有锁定。