Итак, у меня есть этот код, чтобы углубиться в иерархию XML-документов из API REST.Я опубликовал ранее , чтобы получить совет о том, как сделать его рекурсивным, затем я пошел дальше и сделал его parralel.
Во-первых, я был шокирован тем, как быстро он работал - он спустил 318 XMLДокументы менее чем за 12 секунд, по сравнению с более чем 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;
}