Mono/MonoTouch 下的 Task.Factory.StartNew() 延迟

Task.Factory.StartNew() Delay Under Mono / MonoTouch(Mono/MonoTouch 下的 Task.Factory.StartNew() 延迟)

本文介绍了Mono/MonoTouch 下的 Task.Factory.StartNew() 延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Mono 和 MonoTouch 下,我看到调用之间有大约 500 毫秒的延迟:

Under Mono and MonoTouch, I am seeing an approx 500 millisecond delay between when I call:

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

以及工作代码实际开始执行的时间.

and when the worker code actually starts executing.

我创建了一个测试来显示这一点:

I created a test to show this:

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 下的输出:

Output under Mono on 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

就好像 Mono 想要等待最多 500 毫秒以重用现有线程,然后再生成一个新线程.如果我将工作时间减少到 500 毫秒以下,则延迟会减少.比如把worker Thread.Sleep(2000) 改成 Thread.Sleep(50):

It is as if Mono wants to wait up to 500 msec to reuse an existing thread before spawing a new one. If I decrease the worker time below 500 msec, the delay decreases. For example, changing the worker Thread.Sleep(2000) to 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 下,工作代码启动前没有延迟:

But under MS Framework 4.0, no large delay before worker code starts:

...
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.我实际上在我的真实应用程序中使用了最大并发调度程序.

Before I submit a bug report on Mono, I wanted to sanity check that I am not missing some tweak I need to make on Mono or using Task.Factory wrong. I am actually using a max concurrency scheduler in my real app.

所以我的问题是:这是 Mono/MonoTouch 中的错误吗?

So my question: is this a bug in Mono/MonoTouch?

更新:我已经从使用 Mono* 下的 ThreadPool 切换到 Ami Bar 的智能线程池 (github; 代码项目文章).GSerjo 的 扩展线程池 看起来也不错,但是我有很多依赖项试图避免在移动设备上.我在 Xamarim 线程 上写了一些简单的测试.我可能错过了 100 个其他线程池实现,但到目前为止我对 SmartThreadPool 很满意.MonoTouch下使用WINDOWS_PHONE模式编译.

Update: I've switched from using ThreadPool under Mono* to Ami Bar's Smart Thread Pool (github; Code Project article). GSerjo's Extended Thread Pool also looked nice, but had alot of dependencies that I was trying to avoid on mobile. I wrote up some of my simple testing at a Xamarim thread. I probably missed 100 other thread pool implementations, but I've been happy with SmartThreadPool so far. Use WINDOWS_PHONE mode to compile under MonoTouch.

推荐答案

所以我的问题是:这是 Mono/MonoTouch 中的错误吗?

So my question: is this a bug in Mono/MonoTouch?

不一定.我怀疑这只是线程池不愿意每 500 毫秒启动一个以上的新线程.请注意,您会看到 first 任务几乎立即启动.只有在那之后,您才会看到延迟.

Not necessarily. I suspect it's just the thread pool being unwilling to start more than one new thread every 500ms. Note that you're seeing the first task start up pretty much instantly. It's only after that that you're seeing a delay.

如果您在 .NET 4.5 上使用更多任务,您会看到类似的情况,除了每秒启动的块"线程.

If you use more tasks on .NET 4.5, you'll see something similar, except with "chunks" of threads starting each second.

您可能会发现调用 ThreadPool.SetMinThreads 有帮助,假设在 MonoTouch 中可用.

You may find that calling ThreadPool.SetMinThreads helps, assuming that's available in MonoTouch.

这篇关于Mono/MonoTouch 下的 Task.Factory.StartNew() 延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:Mono/MonoTouch 下的 Task.Factory.StartNew() 延迟

基础教程推荐