Вопросы о коде, использующем очередь задач для параллельной сети - PullRequest
4 голосов
/ 16 августа 2011

Итак, у меня есть этот код, чтобы углубиться в иерархию 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;
        }

1 Ответ

1 голос
/ 16 августа 2011

Просто случайно, я не стал бы беспокоиться о коде для управления списком задач, всей блокировке и методе NumTasks ().Было бы проще просто использовать CountdownEvent , который с самого начала безопасен для потоков.Просто увеличивайте его, когда вы создаете новую задачу, и уменьшайте ее, когда задача завершается, вроде как вы делаете сейчас, но без блокировки.

...