在 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;代码项目文章)。GSerjo 的扩展线程池看起来也不错,但有很多我试图在移动设备上避免的依赖项。我在Xamarim 线程上写了一些简单的测试。我可能错过了 100 个其他线程池实现,但到目前为止我对 SmartThreadPool 很满意。在 MonoTouch 下使用 WINDOWS_PHONE 模式编译。