2016-02-04 3 views
2

У меня есть список URL-адресов, которые мне нужно вызвать и выполнить некоторые действия. Это уже работает отлично, но List очень большой, и выполнение занимает очень много времени.пять потоков, работающих над списком задач C#

Я думаю, что я мог бы ускорить работу программы, работая над 5 Urls одновременно с тем, что огромная часть времени выполнения - это программа, ожидающая ответа сервера Urls.

У меня есть список URL-адреса

List<string> urls = getmyurls(); 

А потом я перебор их

for (int i = 0; i < links.Count; i++) 
{ 
    List<string> result = dosomework(urls.ElementAt(i)) 
    urls.AddRange(result); 
} 

Иногда я получаю некоторую дополнительная Urls вернулась, которые должны быть обработано тоже.

(код представляет собой пример, моя текущая программа структурирована немножко diffrent. Это минимальный пример, чтобы объяснить мою проблему.)

Я хочу, пять нитей работает функция «dosomework» в то же время , Всякий раз, когда один из них закончен, я хочу, чтобы он начинался с следующего URL-адреса.

Также: Сколько потоков вы бы выполнили?

+0

Попробуйте найти. Библиотека параллельных taks. – CodeCaster

+1

Если вы хотите быстро, откажитесь от своей упрощенной идеи о том, что больше потоков = больше скорости. Узнайте, как сделать асинхронный ввод-вывод, а не блокировать IO. – spender

+0

Как упоминалось в CodeCaster, TPL - хорошее место для начала. Он определит для вас, сколько задач нужно выполнять параллельно и т. Д. И Parallel.For очень просто положить в –

ответ

1

Когда вы пытаетесь решить URL и вытащить из сети , он похож на вытягивание с диска или чтение из базы данных, поскольку все операции связаны с вводом-выводом. Переход на параллель фактически нежелателен, поскольку больше потоков не помогает, а скорее препятствует производительности. Лучше всего использовать ключевые слова async и await, если вы находитесь на .NET 4.5.

Некоторые люди предлагают Parallel.ForEach, но это лучше всего подходит для задач, связанных с процессором. Для задач, связанных с I/O, вам нужно Task.WhenAll.

Here is great video demonstration О выполнении асинхронных операций с использованием ввода-вывода Джеффри Рихтера. Я настоятельно рекомендую посмотреть его. Тем временем я буду писать ваши итерации так.

private static IEnumerable<string> GetUrls() 
    { 
     return new[] { "https://stackoverflow.com/", "http://www.google.com/" }; 
    } 

    internal async Task Fetch() 
    { 
     var urls = GetUrls(); 
     var tasks = urls.Select(DoWorkAsync); 
     await Task.WhenAll(tasks); 
    } 

    internal Task DoWorkAsync(string url) 
    { 
     // TODO: Implement actual work on the URL in an async manner. 
     return Task.FromResult(url); 
    } 

Идея заключается в том, что вы можете получить URL, и от каждого из URL, выберите задание, которое выполняется на DoWorkAsync. Все они ожидаются.

Update

Похоже, что дроссельный уже ответил here.

+0

Но как я могу узнать (или повлиять), сколько Urls вызывается одновременно. Похоже, что программа вызывает все URL-адреса как можно скорее. –

+0

Это другой вопрос, я ответил на оригинал. Я бы предположил, что если список потенциально огромен, вы можете реализовать какой-то буфер или очередь, а затем пакетные вызовы на N за время. –

+0

Это оригинальная проблема. Список очень огромен. Более 1000 Urls initally и каждая задача потенциально могут добавить еще несколько. –

-1

То, что вы ищете, вероятно, параллельное LINQ.

Рассмотрим пример из https://msdn.microsoft.com/pl-pl/library/dd460714(v=vs.110).aspx

EDIT: Как дело доходит до запуска на несколько потоков добавить WithDegreeOfParallelism(6) где 6 является «нить» сосчитать. Это не совсем 6 нить, но это то, что вы хотите :) Здесь у вас есть хорошее объяснение: http://www.albahari.com/threading/part5.aspx

Также ParallelOptions.MaxDegreeOfParallelism задают максимальный уровень параллелизма

+0

Но не будет ли это исполнять все мои Вызывается сразу. Как я могу определить, сколько паррелейных потоков разрешено сразу? –

+0

«Я думаю, что я мог бы ускорить работу программы, одновременно работая над 5 Urls» Я понял, что это то, что вы хотели :) – badsamaritan

+0

Возможно, я не понимаю этого полностью. Я хочу выполнять свои функции для всех адресов, но только по 5 за раз. Когда бы я ни закончил, я хочу начать с следующего. –

0

Я большой поклонник TPL Dataflow library. Он полностью соответствует этому варианту использования и заслуживает изучения.

Вот необработанная реализация, которая покажет вам, как это работает.

var processURL = new TransformManyBlock<string, string>(url => { 
    return dosomework(url); 
}, 
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5 }); 

var urls = getmyurls(); 
foreach(var url in urls) 
    processURL.Post(url); 

processURL.Completion.Wait(); 
var results = processURL.Receive(); 

Хороший пример процесса трубопровода можно прочитать here.

Смежные вопросы