如何强制Task.Factory.StartNew到后台线程?

Tre*_*ott 13 c# .net-4.0 task threadpool

我已经看到了许多类似的问题,但没有找到我的答案.

我的问题是我用以下流程创建线程:

private void btn_Click(object sender, EventArgs e)
{
    service.GetCount(
        (count, ex) =>
        {
            if (ex != null)
                return;

            for (int i = 0; i < count; i++)
            {
                service.Get(onItemReceived, i);
            }
        }
    );
}

public void GetCount(Action<int, Exception> callback)
{
    var callingThread = TaskScheduler.FromCurrentSynchronizationContext();

    Func<int> action = () =>
    {
        return client.GetCount(); // Synchronous method, could take a long time
    };

    Action<Task<int>> completeAction = (task) =>
    {
        Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;

        if (callback != null)
            callback(task.Result, ex);
    };

    Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread);
}

public void Get(Action<object, Exception> callback, int index)
{
    var callingThread = TaskScheduler.FromCurrentSynchronizationContext();

    Func<object> action = () =>
    {
        return client.Get(index); // Synchronous method, could take a long time
    };

    Action<Task<object>> completeAction = (task) =>
    {
        Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;

        if (callback != null)
            callback(task.Result, ex);
    };

    Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread);
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我的每个服务的异步方法都会回调它们最初调用的线程(通常是UI线程).所以我模拟了await/async关键字是如何工作的(我不能使用.NET 4.5).

这种模式的问题在于,在第一次调用"ContinueWith"之后,我莫名其妙地被锁定到UI线程.所以在这种情况下,如果我尝试为每个进程生成5个线程同步函数Get,它们将逐个执行而不是并行执行,即使我尝试指定TaskCreationOptions.LongRunning,它们也会阻塞UI线程.

我第一次调用Task.Factory.StartNew时就不会发生这种情况,它只发生在第一次回调中的后续调用中.

Tre*_*ott 26

为了强制启动新线程,您应该在对Task.Factory.StartNew的调用中指定TaskScheduler.Default,如下所示:

Task.Factory.StartNew(action,
                      CancellationToken.None,
                      TaskCreationOptions.None,
                      TaskScheduler.Default).ContinueWith(completeAction);
Run Code Online (Sandbox Code Playgroud)

在我的测试中,您不需要指定TaskCreationOptions.LongRunning以强制后台线程,尽管它不应该受到伤害.

  • @Servy - 它不强制任何东西,它是调度程序的_hint_. (3认同)
  • “LongRunning”强制创建一个全新的*非线程池线程*。 (2认同)
  • @HenkHolterman 从理论上讲,是的,这是正确的。实际上,在当前的实现中,它会导致创建一个新线程。虽然我同意最好假设它可能不会运行,但您应该假设将任务标记为长时间运行,而实际上它不会消耗额外的资源。 (2认同)
  • 在上面问题中列出的我的场景中,TaskCreationOptions.LongRunning不强制新的后台线程.只使用TaskScheduler.Default. (2认同)