2012-04-12 3 views
2

У меня есть Семафор, который, как предполагается, ограничивается 3, однако, это просто звонит столько, сколько он хочет. Я предполагаю, что это потому, что я использую (1000). Однако, когда я пытаюсь просто(), он никогда не пройдет WaitOne, я не уверен, что делать здесь.Семафор WaitOne работает некорректно

private static Semaphore _pool; 
_pool = new Semaphore(0, 3); 
var options = new ParallelOptions(); 
options.MaxDegreeOfParallelism = 1; 
Parallel.ForEach(urlTable.AsEnumerable(),options, drow => 
{ 
    using (var WCC = new MasterCrawlerClass()) 
    { 
       ActiveThreads++; 
       _pool.WaitOne(1000); 
       Console.WriteLine("Active Thread #: " + ActiveThreads); 
       WCC.MasterCrawlBegin(drow); 
       Console.WriteLine("Done Crawling a datarow"); 
       ActiveThreads--; 
       _pool.Release(); 

    } 
}); 
+0

Видя, как вы устанавливаете maxdop на 1, что использует Parallel.ForEach, вы действительно купите вас здесь? Тело цикла также, вероятно, будет работать в ThreadPool, где код блокировки большой нет-нет. Вы также должны быть защищены от одновременного доступа к ActiveThreads. Можете ли вы объяснить, что вы пытаетесь сделать здесь? Вероятно, есть лучший способ. – spender

+0

@spender Все, что я хочу сделать, это ограничить количество раз Parallel.Foreach фактически вызывает WCC –

+0

Предел к чему? Не более 3 параллельных обходов? – spender

ответ

6

Вы неправильно управляете семафором. Это должно быть _pool = new Semaphore(3, 3); Выполнение этого также исключает необходимость прохождения в параметре тайм-аута до WaitOne().

Первый параметр - это начальное количество запросов, которое может быть предоставлено перед блокировкой, поэтому передача 0 означает, что последующие вызовы WaitOne() будут немедленно заблокированы.

+0

Это может быть просто из-за того, что я не понимаю, но разве это не первый Int Intum count? Я хочу иметь 0, а затем продолжить, пока у меня не будет 3, а второй int - max, так что должно быть (0,3) –

+1

@Mike Это начальный счет *, который может быть предоставлен *; установка его на 0 означает «вы можете сначала предоставить 0 запросов перед блокировкой», что явно не то, что вы хотите. – dlev

+0

Это может быть не то, что я хочу, в моем цикле foreach он переходит только в один цикл, независимо от того, изменил ли я его на (3,3) или (4,8), почему это –

3

Здесь есть несколько проблем.

  • Я подозреваю, что в этой ситуации нет оснований для параллельного параллелизма в этой ситуации.
  • Вы устанавливаете initialCount в 0 в конструкторе Semaphore. initialCount - количество запросов, которые могут быть предоставлены прямо сейчас.
  • Вы используете перегрузку WaitOne, которая принимает параметр таймаута. По истечении таймаута WaitOne будет возвращаться независимо от того, было ли отсчет отсчетов с семафора.
  • Вы увеличиваете значение ActiveThreadsдо с помощью count с семафора. Это означает, что ActiveThreads более близко приближается к числу одновременных рабочих потоков для операции ForEach. Он не скажет вам, сколько из этих потоков выполняет MasterCrawlBegin.
  • Операция ++ на ActiveThreads не является потокобезопасной.
  • Вы установили MaxDegreesOfParallelism в значение, которое в значительной степени устраняет любую одновременную обработку.

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

int ActiveThreads = 0; 
int ActiveCrawls = 0; 
var semaphore = new SemaphoreSlim(3, 3); 
Parallel.ForEach(urlTable.AsEnumerable(), drow => 
    { 
    int x = Interlocked.Increment(ref ActiveThreads); 
    Console.WriteLine("Active Thread #: " + x); 
    semaphore.Wait(); 
    int y = Interlocked.Increment(ref ActiveCrawls); 
    Console.WriteLine("Active Crawl #: " + y); 
    try 
    { 
     using (var WCC = new MasterCrawlerClass()) 
     { 
     WCC.MasterCrawlBegin(drow); 
     } 
    } 
    finally 
    { 
     Interlocked.Decrement(ref ActiveCrawls); 
     semaphore.Release(); 
     Interlocked.Decrement(ref ActiveThreads); 
     Console.WriteLine("Done Crawling a datarow"); 
    } 
    } 
}); 

И, конечно, вы можете просто установить MaxDegreesOfParallelism = 3 и не беспокоиться обо всех семафоров вещи.

+0

Обратитесь к моему [отвечу] (http://stackoverflow.com/a/10116536/158779) здесь для дальнейшего анализа вашей проблемы и причины, по которой я думаю, что дросселирование параллелизма - плохая идея в этой ситуации. –