6

Mono と MonoTouch では、次の呼び出しの間に約 500 ミリ秒の遅延が見られます。

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

ワーカーコードが実際に実行を開始したとき。

これを示すテストを作成しました:

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

Mac の Mono での出力:

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

Mono は、新しいスレッドを生成する前に、既存のスレッドを再利用するために最大 500 ミリ秒待機する必要があるかのようです。ワーカー時間を 500 ミリ秒未満に減らすと、遅延が減少します。たとえば、ワーカー Thread.Sleep(2000) を Thread.Sleep(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

しかし、MS Framework 4.0 では、ワーカー コードが開始されるまでに大きな遅延はありません。

...
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

Mono のバグ レポートを送信する前に、Mono で行う必要のある微調整や、Task.Factory の使用方法が間違っていないかどうか、サニティ チェックを行いたいと思いました。私は実際に実際のアプリで最大同時実行スケジューラを使用しています。

私の質問: これは Mono/MonoTouch のバグですか?

更新: Mono* での ThreadPool の使用から、Ami Bar のスマート スレッド プール ( github ; Code Project article ) に切り替えました。GSerjo のExtended Thread Poolも良さそうに見えましたが、モバイルでは避けようとしていた多くの依存関係がありました。Xamarim スレッドで簡単なテストをいくつか書きました。おそらく他に 100 個のスレッド プールの実装を見逃していますが、これまでのところ SmartThreadPool には満足しています。MonoTouch でコンパイルするには、WINDOWS_PHONE モードを使用します。

4

1 に答える 1

6

私の質問: これは Mono/MonoTouch のバグですか?

必ずしも。スレッド プールが 500 ミリ秒ごとに複数の新しいスレッドを開始したくないだけだと思います。最初のタスクがほぼ瞬時に開始されることに注意してください。遅延が発生するのはその後です。

.NET 4.5 でさらに多くのタスクを使用すると、1 秒ごとに開始されるスレッドの「チャンク」を除いて、同様のことがわかります。

ThreadPool.SetMinThreadsMonoTouch で利用できると仮定すると、呼び出しが役立つことがわかる場合があります。

于 2012-11-01T22:18:35.923 に答える