2013-03-03 28 views
7

OK tutaj moje pytanie. Chcę rozpocząć wątki do pewnej liczby. Powiedzmy, że 100. Więc zacznie zaczynać wątki i sprawdzać ciągle liczbę uruchomionych wątków. Gdy osiągnięta liczba maksymalna przestanie zaczynać nowe wątki. Ale z odpowiednim interwałem sprawdzania lub zakończonym wątkiem zasygnalizuje i rozpocznie nowy wątek.Jak ustawić pewną liczbę wątków działających cały czas

W ten sposób zawsze będę mieć określoną liczbę uruchomionych wątków.

Udało mi się to przy użyciu snu i na stałe podczas. Sprawdzam więc całkowitą liczbę wątków w danym przedziale i jeśli wątek jest zakończony, wyrzuć go i rozpocznij nowy.

Ale moje rozwiązanie nie przychodzi mi właściwie. Przypuszczam, że byłoby lepiej, gdyby zakończony wątek zasygnalizował, a następnie sprawdzanie uruchomiłoby nowy, gdybyśmy byli poniżej maksymalnej liczby progów wątków.

Widziałem wiele przykładów wątków, ale większość z nich nie zawiera żadnego buforowania w kolejce z maksymalną ilością uruchomionych wątków. Chodzi mi o to, że oni po prostu zaczynają wątki, dopóki nie skończą. Ale powiedzmy, że mam 500k adresów do zbioru. Nie mogę po prostu uruchomić ich wszystkich w pętli for z pulą wątków.

platforma C# 4.5 aplikacji WPF

A tu poniżej jest moje rozwiązanie. Właściwie szukam lepszego. Nie poprawiam tego.

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    Task.Factory.StartNew(() => 
    { 
     startCrawler(); 
    }); 
} 

void startCrawler() 
{ 
    int irMaximumThreadcount = 100; 
    List<Task> lstStartedThreads = new List<Task>(); 
    while (true) 
    { 
     for (int i = 0; i < lstStartedThreads.Count; i++) 
     { 
      if (lstStartedThreads[i].IsCompleted == true) 
      { 
       lstStartedThreads[i].Dispose(); 
       lstStartedThreads.RemoveAt(i); 
      } 
     } 

     if (lstStartedThreads.Count < irMaximumThreadcount) 
     { 
      var vrTask = Task.Factory.StartNew(() => 
      { 
       func_myTask(); 
      }); 
      lstStartedThreads.Add(vrTask); 
     } 

     System.Threading.Thread.Sleep(50); 
    } 
} 

void func_myTask() 
{ 

} 
+0

"Nie mogę po prostu uruchomić ich wszystkich w pętli for z pulą wątków." - czy naprawdę próbowałeś? Uruchomienie wielu wątków z założeniem, że sprawi, że twoje ogólne połączenie internetowe będzie szybsze, nie brzmi "tak jak należy". Także conisder używający operacji asynchronicznych - nie będzie potrzebował tylu wątków ... Jeśli nie masz czegoś takiego jak maszyna 32-rdzeniowa ... –

Odpowiedz

6

osobiście byłoby użyć PLINQ do tego, a dokładniej metodą WithDegreeOfParallelism co ogranicza liczbę jednoczesnych wykonaniach do przekazany wartości.

private IEnumerable<Action> InfiniteFunctions() 
{ 
    while(true) 
    { 
     yield return func_myTask; 
    } 
} 

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    int irMaximumThreadcount = 100; 
    InfiniteFunctions() 
     .AsParallel() 
     .WithDegreeOfParallelism(irMaximumThreadcount) 
     .ForAll(f => f()); 
} 

EDIT: Właściwie czytanie dokumentacji wydaje się, że irMaximumThreadCount może być tylko max 64 więc uważaj na to.

EDIT 2: Ok, miał lepszy wygląd i wydaje Parallel.ForEach przyjmuje parametr ParallelOptions który zawiera MaxDegreeOfParallelism właściwość, która nie jest ograniczona - Check it out. Twój kod może wyglądać następująco:

private void CrawlWebsite(string url) 
{ 
    //Implementation here 
} 

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    var options = new ParallelOptions() 
    { 
     MaxDegreeOfParallelism = 2000 
    }; 

    Parallel.ForEach(massiveListOfUrls, options, CrawlWebsite); 
} 
+0

to jest teraz interesujące. więc mówisz, że ta metoda może być używana na przykład do indeksowania 500 tys. stron. pozwól mi spróbować :) – MonsterMMORPG

+0

oh. to jest dla mnie bezużyteczne :) zaczynam 2000 wątków, aby sprawdzić żywych serwerów proxy na przykład^^ chociaż menedżer zadań pokazuje 490 wątków. Nie wiem czemu nie 2000 :) – MonsterMMORPG

+0

Ah, uważaj na moją edycję - max to tylko 64 równolegle. I tak, możesz zapętlić swoją listę 500 000 przedmiotów i wykonać funkcję na każdym elemencie. – Felix

0

Nie jest to dokładna odpowiedź, ale myślę, że to może Cię poprowadzić we właściwym kierunku.

Najpierw spójrz na Thread.Join, szczególnie na prosty przykład podany na dole tej strony. To podejście jest lepsze niż Thread.Sleep() i bardziej odpowiednie dla twojego celu. Zastanawiam się nad liniami * Dołączając do * wątku "menedżera" zamiast * Uśpienie * ing.

Drugą opcją, która może lub nie jest odpowiednia, jest nowa biblioteka Tasks. Ponieważ używasz najnowszej wersji architektury, ta opcja jest dostępna, ale domyślam się, że nie możesz kontrolować faktycznej liczby wątków utworzonych przez bibliotekę zadań. Automatycznie wybiera tę wartość w oparciu o podstawowy harmonogram. Istnieje jednak opcja o nazwie ParallelOptions.MaxDegreeOfParallelism, która brzmi interesująco.

+0

, o ile wiem, że łączenie wątków służy do oczekiwania na zakończenie wszystkich zadań. czy jestem niepoprawny? jeśli tak, jak mogę go użyć? Nie muszę czekać na wszystkie zadania. gdy 1 zadanie zostanie zakończone, inny rozpocznie się natychmiast, więc zawsze będzie pewna liczba zadań z uruchomieniem – MonsterMMORPG

+0

mmmm ... Nie jestem w 100% pewny, ale myślę, że Join tylko zatrzymuje wątek wywołujący.Innym pomysłem może być dołączenie do nowo utworzonych wątków roboczych, aby natychmiast rozpocząć pracę, gdy jeden z aktualnie uruchomionych wątków sygnalizuje, że jest kompletny, więc menedżer nie musi sprawdzać w kółko. – dotNET

+0

nie, to nie działa. ponieważ wątki są samodzielnie zakończone. pierwszy rozpoczęty może zakończyć ostatni lub ostatni start może zakończyć się jako pierwszy. – MonsterMMORPG

1

. NET 4.0 wprowadził kilka kolekcji z wbudowanym zarządzaniem współbieżnością, które powinny być idealne dla tej sytuacji. Kolekcja blokująca będzie bardziej skuteczna niż spanie w pętli. Następnie odradzasz x wątków odczytywanych z kolejki blokującej.

BlockingCollection<string> queue = new BlockingCollection<string>(listOfUrls); 

for (int x=0; x < MaxThreads; x++) 
{ 
    Task.Factory.StartNew(() => 
    { 
     while (true) 
     { 
      string url = queue.Take(); // blocks until url is available 
      // process url; 
     } 
    }, TaskCreationOptions.LongRunning); 
} 

Oznacz to zadanie jako działające długo, więc utworzy własny wątek zamiast używać puli wątków. Jeśli potrzebujesz pierwszego na początku, możesz przekazać ConcurrentQueue<T> do blokującego konstruktora kolekcji. http://msdn.microsoft.com/en-us/library/dd287085.aspx

3

Wymieszać zadania z wątkami. Zadanie nie jest wątkiem. There is no guarantee that each task will have it's own thread.

W rzeczywistości TPL (Task Parallel Library) jest jakimś rodzajem kolejki. Oznacza to, że możesz po prostu tworzyć i uruchamiać zadania dla każdego posiadanego obiektu Func lub Action. There is no easy way to control the number of threads które zostały faktycznie utworzone.

Można jednak utworzyć wiele zadań przy niewielkim obciążeniu, ponieważ TPL spowoduje ich dodanie do kolejki i zastosowanie dodatkowej logiki w celu zrównoważenia pracy nad wątkami thread pool.

Jeśli niektóre zadania muszą być wykonywane jeden po drugim, można użyć Task.ContinueWith, aby je zamonetować. Możliwe jest również uruchamianie nowych zadań za pomocą Task.Factory.ContinueWhenAny lub Task.Factory.ContinueWhenAll.

Jest to również wskazówka, w jaki sposób można kontrolować liczbę zadań równoległych, które chcesz utworzyć: Po prostu utwórz żądaną liczbę zadań i umieść pozostałe zadania w postaci ContinueWhenAny. Za każdym razem, gdy kończy się zadanie, rozpocznie się następny.

Jeszcze raz: licencja OC wyrówna pracę między wątkami w puli wątków. To, co i tak należy wziąć pod uwagę, to wykorzystanie innych zasobów, takich jak dyskowe I/O lub połączenie internetowe. Posiadanie wielu zadań, które próbują jednocześnie korzystać z tych samych zasobów, może drastycznie spowolnić twój program.

+0

Mam dużo zasobów. 850 MB na sekundę Odczyt prędkości odczytu I/O, połączenie światłowodowe 50 Mb. W każdym razie jest to kilka przydatnych informacji głosujących w górę :) – MonsterMMORPG