2013-03-03 15 views
7

Ok qui la mia domanda. Voglio iniziare le discussioni fino a un certo numero. Diciamo 100. Quindi inizierà a iniziare i thread e controllerà continuamente il numero di thread in esecuzione. Quando raggiunge il numero massimo, smetterà di iniziare nuovi thread. Ma con un adeguato intervallo di controllo o thread completato segnalerà e inizierà la nuova discussione.Come fare un certo numero di thread sempre in esecuzione

Con questo modo, avrò sempre certo numero di thread in esecuzione.

Ho gestito questo con l'uso di sonno e permanente mentre. Quindi continuo a controllare il numero totale di thread in esecuzione con un determinato intervallo e, se il thread è completo, lo dispongo e ne avvio uno nuovo.

Ma la mia soluzione non è venuta a me come un modo corretto. Suppongo che sarebbe meglio se il thread completato segnalasse e quindi il controllore ne inizierebbe uno nuovo se siamo al di sotto del numero massimo di soglia dei thread.

ho visto molti esempi ThreadPool ma la maggior parte di loro non contiene alcuna coda pooling con importo massimo di thread in esecuzione. Quello che voglio dire è che continuano a iniziare le discussioni finché non sono terminate. Ma diciamo che ho 500k di url da raccogliere. Non posso solo avviarli tutti in un ciclo for con il pool di thread.

piattaforma è C# 4.5 applicazione WPF

E qui sotto è la mia soluzione. In realtà sto cercando uno migliore. Non migliorare questo.

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

"Non posso solo avviarli tutti in un ciclo for con pool di thread." - hai effettivamente provato? Avvio di più thread con l'ipotesi che renderà più veloce la connessione Internet globale non suona "come un modo corretto". Anche conisder usando operazioni asincrone - non avrà bisogno di molti thread ... A meno che tu non abbia qualcosa come la macchina 32-core ... –

risposta

6

Personalmente utilizzare PLINQ per questo, e in particolare il metodo WithDegreeOfParallelism che limita il numero di esecuzioni simultanee al passato in valore.

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: In realtà la lettura della documentazione sembra che irMaximumThreadCount può essere solo un massimo di 64 in modo da guardare fuori per questo.

EDIT 2: Ok, aveva un aspetto migliore e sembra Parallel.ForEach prende un parametro ParallelOptions, che include una proprietà MaxDegreeOfParallelism che non è limitato - Check it out. Quindi il tuo codice potrebbe essere:

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

ora questo è interessante. quindi dici che questo metodo può essere utilizzato ad esempio per la scansione di pagine 500k. fammi provare :) – MonsterMMORPG

+0

oh. quindi è inutile per me :) sto iniziando 2000 thread per controllare proxy vivi per esempio ^^ anche se il task manager mostra 490 thread. non so perché non 2000 :) – MonsterMMORPG

+0

Ah, attenzione per la mia modifica - max è solo 64 in parallelo. E sì, è possibile scorrere l'elenco di 500.000 articoli ed eseguire la funzione su ciascun elemento. – Felix

0

Non è una risposta esatta, ma penso che questo possa guidarti nella direzione corretta.

In primo luogo, dare un'occhiata a Thread.Join, in particolare il semplice esempio dato in fondo a questa pagina. Questo approccio è superiore a Thread.Sleep() e più adatto al tuo scopo. Sto pensando sulle linee di * Registrazione * ing il "manager" filo invece di * sonno * ing.

La seconda opzione che possono o non possono soddisfare il vostro scopo, è il nuovo Tasks biblioteca. Dato che stai usando l'ultima versione del framework, questa opzione è disponibile, ma suppongo che tu non possa controllare il numero effettivo di thread creati dalla libreria Task. Sceglie automaticamente quel valore in base allo scheduler sottostante. Tuttavia, c'è un'opzione denominata ParallelOptions.MaxDegreeOfParallelism che sembra interessante.

+0

per quanto ne so, il thread join è utilizzato per attendere tutte le operazioni. sono errato? se sì, come posso usarlo? non ho bisogno di aspettare tutte le attività. quando 1 task è terminato, un altro verrà avviato immediatamente, quindi ci sarà sempre un certo numero di attività in esecuzione – MonsterMMORPG

+0

mmmm ... Non sicuro al 100%, ma credo che Join interrompa solo il thread chiamante.Un'altra idea potrebbe essere quella di unire i thread di lavoro appena creati in modo che inizino a funzionare immediatamente dopo che uno dei thread attualmente in esecuzione segnala che è completo, quindi il gestore non deve controllarlo più e più volte. – dotNET

+0

no che non funzionerebbe. perché i fili sono finiti indipendentemente. il primo iniziato potrebbe finire ultimo o l'ultimo iniziato potrebbe finire per primo. – MonsterMMORPG

1

.NET 4.0 ha introdotto diverse raccolte con la gestione della concorrenza integrata che dovrebbe essere l'ideale per questa situazione. Una raccolta di blocchi sarà più efficace quindi dormendo in un ciclo di tempo. Quindi si generano solo x thread letti dalla coda di blocco.

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); 
} 

È possibile contrassegnare l'attività come a lungo in esecuzione in modo da creare il proprio thread anziché utilizzare il pool di thread. Se è necessario innanzitutto il primo passaggio, è possibile passare un ConcurrentQueue<T> al costruttore della raccolta di blocchi. http://msdn.microsoft.com/en-us/library/dd287085.aspx

3

Si confondono le attività con i thread. Un'attività non è un thread. There is no guarantee that each task will have it's own thread.

In realtà il TPL (Task Parallel Library) è una specie di coda. Ciò significa che puoi creare e avviare attività per ogni oggetto Func o Action che hai. There is no easy way to control the number of threads effettivamente creati.

Tuttavia, è possibile creare molte attività con un piccolo sovraccarico perché il TPL le accoderà e applicherà ulteriore logica per bilanciare il lavoro sui thread dello thread pool.

Se alcune attività devono essere eseguite una dopo l'altra, è possibile utilizzare Task.ContinueWith per accodarle. È anche possibile iniziare nuove attività con Task.Factory.ContinueWhenAny o Task.Factory.ContinueWhenAll.

Questo è anche l'indizio su come è possibile controllare il numero di attività parallele che si desidera creare: basta creare il numero desiderato di attività e accodare le attività rimanenti con ContinueWhenAny. Ogni volta che un compito termina, il successivo verrà avviato.

Ancora: il TPL bilancia il lavoro tra i thread nel pool di thread. Quello che devi considerare in ogni caso è l'uso di altre risorse come l'I/O del disco o la connessione Internet. Avere un sacco di compiti che cercano di utilizzare contemporaneamente le stesse risorse può rallentare drasticamente il tuo programma.

+0

Ho molte risorse. I/O da 850 MB al secondo velocità di scrittura in lettura, connessione a 50 mbit in fibra. Comunque questo è qualche informazione utile vota :) – MonsterMMORPG

Problemi correlati