2013-03-29 2 views
4

Я хочу создать программу для сканирования и проверки моих сайтов на наличие ошибок http и других вещей. Я хочу сделать это с помощью нескольких потоков, которые должны принимать параметры, такие как URL для сканирования. Хотя я хочу, чтобы потоки X были активны, есть Y Задачи, ожидающие выполнения.Лучший многопоточный подход для нескольких веб-запросов

Теперь я хотел знать, что является лучшей стратегией для этого: ThreadPool, задачи, темы или даже что-то еще?

+1

попробовать это http://stackoverflow.com/questions/4277844/multithreading- a-large-of-web-request-in-c-sharp – Niventh

+0

«best» довольно сложно определить. Я предлагаю вам изучить «Связанные» вопросы (справа, внизу) и выбрать тот, который, по вашему мнению, будет лучше всего соответствовать вашему приложению. Вероятно, задачи - это путь, но это все еще оставляет много возможностей для разнообразия. –

ответ

0

Хорошо, Task - хороший способ пойти, потому что это будет означать, что вам не нужно беспокоиться о написании большого количества «сантехнического» кода.

Я рекомендую вам проверить веб-сайт Джо Albahari на резьб, а также, это довольно хороший учебник по резьбе:

http://www.albahari.com/threading/

0

Я рекомендовал бы с Threadpool. Достаточно легко работать, так как он имеет несколько преимуществ:

«Пул потоков предоставит преимущества для частых и относительно коротких операций Повторное использование потоков, которые уже созданы вместо создания новых (дорогостоящий процесс) Регулирование скорости создания потоков при появлении запросов на новые рабочие элементы (я считаю, что это только в .NET 3.5)

Если вы ставите в очередь 100 задач пула потоков, он будет использовать столько потоков, сколько имеет уже созданы для обслуживания этих запросов (например, например, 10). Пул потоков будет часто проверять (я считаю, каждые 500 мс в 3.5 SP1), и если есть задачи с постами, он будет создавать новый поток. Если ваши задачи быстрые, то число новых потоков будет небольшим, и повторное использование 10 или около того потоков для коротких задач будет быстрее, чем создание 100 потоков вверх.

Если в вашей рабочей нагрузке постоянно поступает большое количество запросов пула потоков, тогда пул потоков настроится на вашу рабочую нагрузку, создав больше потоков в пуле описанным выше процессом, чтобы было доступно большее количество потоков для обрабатывать запросы»

Thread vs ThreadPool

5

Вот пример, который показывает, как очереди кучи задач, но ограничить количество, которые одновременно работает. Он использует Queue для отслеживания задач, которые готовы работать и использование a Dictionary, чтобы отслеживать выполняемые задачи. Когда задача завершается, он вызывает метод обратного вызова для восстановления ove себя от Dictionary. Метод async используется для запуска задач с очередями по мере того, как пространство становится доступным.

using System; 
using System.Collections.Generic; 
using System.Threading; 
using System.Threading.Tasks; 

namespace MinimalTaskDemo 
{ 
    class Program 
    { 
     private static readonly Queue<Task> WaitingTasks = new Queue<Task>(); 
     private static readonly Dictionary<int, Task> RunningTasks = new Dictionary<int, Task>(); 
     public static int MaxRunningTasks = 100; // vary this to dynamically throttle launching new tasks 

     static void Main(string[] args) 
     { 
      var tokenSource = new CancellationTokenSource(); 
      var token = tokenSource.Token; 
      Worker.Done = new Worker.DoneDelegate(WorkerDone); 
      for (int i = 0; i < 1000; i++) // queue some tasks 
      { 
       // task state (i) will be our key for RunningTasks 
       WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((int)id, token), i, token)); 
      } 
      LaunchTasks(); 
      Console.ReadKey(); 
      if (RunningTasks.Count > 0) 
      { 
       lock (WaitingTasks) WaitingTasks.Clear(); 
       tokenSource.Cancel(); 
       Console.ReadKey(); 
      } 
     } 

     static async void LaunchTasks() 
     { 
      // keep checking until we're done 
      while ((WaitingTasks.Count > 0) || (RunningTasks.Count > 0)) 
      { 
       // launch tasks when there's room 
       while ((WaitingTasks.Count > 0) && (RunningTasks.Count < MaxRunningTasks)) 
       { 
        Task task = WaitingTasks.Dequeue(); 
        lock (RunningTasks) RunningTasks.Add((int)task.AsyncState, task); 
        task.Start(); 
       } 
       UpdateConsole(); 
       await Task.Delay(300); // wait before checking again 
      } 
      UpdateConsole(); // all done 
     } 

     static void UpdateConsole() 
     { 
      Console.Write(string.Format("\rwaiting: {0,3:##0} running: {1,3:##0} ", WaitingTasks.Count, RunningTasks.Count)); 
     } 

     // callback from finished worker 
     static void WorkerDone(int id) 
     { 
      lock (RunningTasks) RunningTasks.Remove(id); 
     } 
    } 

    internal class Worker 
    { 
     public delegate void DoneDelegate(int taskId); 
     public static DoneDelegate Done { private get; set; } 
     private static readonly Random Rnd = new Random(); 

     public async void DoWork(object id, CancellationToken token) 
     { 
      for (int i = 0; i < Rnd.Next(20); i++) 
      { 
       if (token.IsCancellationRequested) break; 
       await Task.Delay(100); // simulate work 
      } 
      Done((int)id); 
     } 
    } 
} 
+0

Привет, какова цель цикла 'for' с' Rnd' ..? Это one => 'for (int i = 0; i Shiva

+1

@Shiva - цикл просто имитирует некоторое количество выполняемой работы. –

+0

Спасибо. Поэтому, если бы я выполнял фактическую работу в строке 'await ...' метода DoWork, я бы удалил этот цикл 'for'. В этом случае я бы использовал 'if (token.IsCancellationRequested) return;' вместо 'if (token.IsCancellationRequested) break;'? – Shiva

2

Я рекомендую использовать (асинхронный) Task с для загрузки данных, а затем обработку (в пуле потоков).

Вместо задач дросселирования я рекомендую вам активировать количество запросов на целевой сервер. Хорошие новости: .NET already does this for you.

Это делает ваш код просто:

private static readonly HttpClient client = new HttpClient(); 
public async Task Crawl(string url) 
{ 
    var html = await client.GetString(url); 
    var nextUrls = await Task.Run(ProcessHtml(html)); 
    var nextTasks = nextUrls.Select(nextUrl => Crawl(nextUrl)); 
    await Task.WhenAll(nextTasks); 
} 
private IEnumerable<string> ProcessHtml(string html) 
{ 
    // return all urls in the html string. 
} 

, который вы можете начать с простого:

await Crawl("http://example.org/"); 
Смежные вопросы