2016-07-04 6 views
0

Ich bin ein C# -Programmierer, und ich laufe in einige Thread Problem Problem.C# Diversifikation Thread gleichermaßen

Assets Einheiten sind, und ich brauche jede Anlage parallel laufen zu lassen, und ein Verfahren „doSomethingOnAsset“ laufen

Ich habe ein Programm, das 100 Gewinde (dh 1 Thread pro Asset ich es einige Manipulationen tue) hat . Im Allgemeinen hat jeder Thread den gleichen Zeitrahmen für jedes laufende Intrval, und jeder ruft "doSomethingOnAsset" -Methode auf.

Jedes Thread-Intervall läuft 10 Millisekunden (d. H.).

Ich möchte nicht so viele Threads, so dass ich eine Warteschlange für jedes Asset erstellen, aber beim Aufruf der zentralen Methode "doSomethingOnAsset" - die Threads nicht im gleichen Zeitrahmenintervall laufen.

, d.h. der 1. Thread-Laufintervallzyklus beträgt 300 Millisekunden. Der 2. Thread-Laufintervallzyklus beträgt 700 Millisekunden. der dritte Thread läuft Intervall Zyklus ist 2 Sekunden. ...

Was ist der beste Weg, um eine vordefinierte Methode 100mal parallel (der parallel Eintrag läuft ein externer Dienst sein kann, dass beim Laufen, ein Ereignis auslösen, die meinen Code von „doSomethingOnAsset“ läuft.

public void doSomethingOnAsset(object obj) 
{ 
    // infinite loop when thread. 
    while (true) 
    { 
     doSomething(obj); 
     Thread.Sleep(100); 
    } 
} 

public void doSomething(object obj) 
{ 
    // do something. 
} 

public void Run() 
{ 
    Thread t;    
    for (int i = 0; i < 100; i++) 
    { 
     t = new Thread(new ParameterizedThreadStart(this.doSomethingOnAsset)); 
     t.Start(new object()); 
    } 

    Console.ReadLine(); 
} 

oder doSomething auf Ereignissignal rufen, wenn ein externes Programm Trigger.

Thanks :)

+2

Randnotiz. Warum nicht 'Parallel.Für (...)'? 100-Threads explizit zu erstellen ist kein gutes Design. Etwa so: 'Parallel.For (0, 100, i => doSomethingOnAsset (i));' –

+0

Entweder 'Parallel.For' verwenden oder alle mit dem Threadpool in die Warteschlange stellen oder mit Tasks, die Parallelität sollte automatisch erledigt werden . –

+2

Haben Sie 100 Kerne? Dies klingt nicht nach einem guten Plan zur Optimierung des Durchsatzes. – spender

Antwort

1

Für diese Art von Erzeugung und Verbrauchern Situationen, die ich eine blockierende Sammlung in der Regel definieren, definieren und eine consu erstellen mer (oder mehrere) und beginnen Sie, der Sammlung Daten hinzuzufügen. Jede Verbraucherinstanz versucht, einen Artikel zu übernehmen und ihn gegebenenfalls zu verbrauchen. Andernfalls wird auf einen Artikel gewartet.

Sie könnten ein Abbruch-Token hinzufügen, um die Verarbeitung zu stoppen.

Sie können es problemlos skalieren, indem Sie mehr Konsumenten hinzufügen. Welche Nummer am effizientesten ist, hängt natürlich von der Maschine und der Anzahl der Kerne in Kombination mit der Verarbeitungslänge pro Artikel ab.

Der Verbraucher:

public class MyConsumer<T> { 
    public MyConsumer(BlockingCollection<T> collection, Action<T> action) { 
     _collection = collection; 
     _action = action; 
    } 

    private readonly BlockingCollection<T> _collection; 
    private readonly Action<T> _action; 

    public void StartConsuming() { 
     new Task(Consume).Start(); 
    } 

    private void Consume() { 
     while (true) { 
      var obj = _collection.Take(); 
      _action(obj); 
     } 
    } 
} 

Verbrauch:

public void doSomething(object obj) { 
    // do something. 
} 

public void Run() { 
    var collection = new BlockingCollection<object>(); 

    // Start workers 
    for (int i = 0; i < 5; i++) { 
     new MyConsumer<object>(collection, doSomethingOnAsset); 
    } 

    // Create object to consume 
    for (int i = 0; i < 100; i++) { 
     collection.Add(new object()); 
    } 
} 
+0

Keine Notwendigkeit, kalte Aufgaben zu verwenden, dh 'Task (Consume) .Start()', 'Task.Run' wird tun. Außerdem muss * ein Task/Thread, der auf eine Eingabe wartet, blockiert werden. Der ActionBlock des Frameworks tut dies bereits ohne Blockierung und viel bessere Kontrolle über Pufferung, DOP –