2012-11-01 11 views
6

unter Mono und Monotouch, ich sehe eine ca. 500 Millisekunden Verzögerung zwischen wenn ich rufe:Task.Factory.StartNew() Verzögerung unter Mono/Monotouch

StartNew(Action<object> action, object state, CancellationToken cancellationToken, 
    TaskCreationOptions creationOptions, TaskScheduler scheduler); 

und wenn der Arbeitnehmer die Ausführung von Code tatsächlich beginnt.

habe ich einen Test, dies zu zeigen:

public static class TestTaskFactory 
{ 
    private class TaskInfo 
    { 
     public int Number; 
    } 

    private static int NUM_TASKS = 5; 
    private static int NumFinished = 0; 

    public static void Run() 
    { 
     for (int n = 1; n <= NUM_TASKS; n++) 
     { 
      Log("Starting task #" + n + " ..."); 
      var task_info = new TaskInfo { Number = n }; 
      var task = Task.Factory.StartNew(Worker, task_info, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); 
      Thread.Sleep(0); 
     } 

     Log("Waiting for tasks to finish ..."); 
     while (NumFinished < NUM_TASKS) 
     { 
      Thread.Sleep(1); 
     } 

     Log("All done"); 
    } 

    private static void Worker(object state) 
    { 
     var task_info = (TaskInfo)state; 
     Log("Task #" + task_info.Number + " running"); 

     // Do something 
     Thread.Sleep(2000); 

     // Done 
     ++NumFinished; 
    } 

    private static void Log(string msg) 
    { 
     Console.WriteLine(DateTime.Now.ToString("HH.mm.ss.fff") + ": Thread " + Thread.CurrentThread.ManagedThreadId + ": " + msg); 
    } 
} 

Ausgabe unter Mono auf Mac:

16.57.31.420: Thread 1: Starting task #1 ... 
16.57.31.508: Thread 1: Starting task #2 ... 
16.57.31.508: Thread 1: Starting task #3 ... 
16.57.31.508: Thread 1: Starting task #4 ... 
16.57.31.508: Thread 1: Starting task #5 ... 
16.57.31.508: Thread 1: Waiting for tasks to finish ... 
16.57.31.510: Thread 5: Task #1 running 
16.57.32.009: Thread 6: Task #2 running <-- Approx 500 msec later 
16.57.32.511: Thread 7: Task #3 running <-- Approx 500 msec later 
16.57.33.012: Thread 8: Task #4 running <-- Approx 500 msec later 
16.57.33.513: Thread 9: Task #5 running <-- Approx 500 msec later 
16.57.35.515: Thread 1: All done 

Es ist, als ob Mono will 500 ms warten, bis einen bestehenden Faden wieder zu verwenden, bevor spawing ein neues. Wenn ich die Arbeitszeit unter 500 ms verringere, nimmt die Verzögerung ab. Um zum Beispiel die Arbeiter Thread.Sleep (2000) auf Thread.Sleep Wechsel (50):

... 
17.13.20.262: Thread 5: Task #1 running 
17.13.20.314: Thread 5: Task #2 running <-- approx 50 msec later 
17.13.20.365: Thread 5: Task #3 running <-- approx 50 msec later 
17.13.20.416: Thread 5: Task #4 running <-- approx 50 msec later 
17.13.20.466: Thread 5: Task #5 running <-- approx 50 msec later 

Aber unter MS Framework 4.0, keine große Verzögerung, bevor Arbeiter Code beginnt:

... 
17.05.42.238: Thread 9: Waiting for tasks to finish ... 
17.05.42.256: Thread 11: Task #1 running 
17.05.42.256: Thread 12: Task #3 running <-- little delay 
17.05.42.256: Thread 13: Task #4 running <-- little delay 
17.05.42.257: Thread 10: Task #2 running <-- little delay 
17.05.43.264: Thread 14: Task #5 running <-- little delay 

Bevor ich einen Fehlerbericht über Mono einreichte, wollte ich überprüfen, dass ich nicht ein paar Optimierungen vermisse, die ich bei Mono machen oder Task.Factory falsch verwenden muss. Ich verwende tatsächlich einen Max-Concurrency-Scheduler in meiner echten App.

Also meine Frage: Ist das ein Fehler in Mono/MonoTouch?

Update: Ich habe von ThreadPool unter Mono * zu Smart Thread Pool (github; Code Project article) gewechselt. GSerjo's Extended Thread Pool sah auch gut aus, hatte aber viele Abhängigkeiten, die ich auf dem Handy vermeiden wollte. Ich schrieb einige meiner einfachen Tests unter Xamarim thread. Ich habe wahrscheinlich 100 andere Thread-Pool-Implementierungen verpasst, aber bisher war ich mit SmartThreadPool zufrieden. Verwenden Sie den WINDOWS_PHONE-Modus, um unter MonoTouch zu kompilieren.

Antwort

6

Also meine Frage: Ist das ein Fehler in Mono/MonoTouch?

Nicht unbedingt. Ich vermute, dass es nur der Thread-Pool ist, der nicht alle 500ms mehr als einen neuen Thread starten möchte. Beachten Sie, dass Sie die erste Aufgabe so ziemlich sofort starten sehen. Erst danach sehen Sie eine Verzögerung.

Wenn Sie mehr Aufgaben in .NET 4.5 verwenden, sehen Sie etwas Ähnliches, mit Ausnahme von "Brocken" von Threads, die jede Sekunde beginnen.

Sie können feststellen, dass der Aufruf hilft, vorausgesetzt, dass in MonoTouch verfügbar ist.

+0

Ja, SetMinThreads() hat es geschafft. Der Wert von 500 ms scheint sehr willkürlich. Das ist eine super lange Zeit sogar unter iOS, geschweige denn Mono für Mac, wo ich das auch sehe. Basierend auf Quick Googlen kann dies eine Konstante aus einer bestimmten Version von MS Framework sein. Ich werde mehr recherchieren/experimentieren und berichten. Mono-Defaults fühlen sich nicht richtig für mich an. – t9mike

+0

@ t9mike: Ja, ich denke, das war das Timing vor .NET 4, wo der Thread-Pool ziemlich komplett neu geschrieben wurde, glaube ich. –

+4

Der langsame Start für Threads im Threadpool ist da, um einen Threadsturm zu vermeiden. –

Verwandte Themen