Как заставить Task.Factory.StartNew использовать фоновый поток?

Я видел множество других вопросов, подобных этому, но не нашел там своего ответа.

Моя проблема заключалась в том, что я создавал потоки со следующим потоком:

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

Таким образом, каждый из моих асинхронных методов службы вызывал бы обратный поток, из которого они были первоначально вызваны (как правило, поток пользовательского интерфейса). Поэтому я имитирую работу ключевых слов await/async (я не могу использовать .NET 4.5).

Проблема с этим шаблоном заключается в том, что я необъяснимо заблокирован для потока пользовательского интерфейса после первого вызова "ContinueWith". Поэтому в этом случае, если я попытаюсь создать 5 потоков для каждого процесса синхронной функцией Получить, они будут выполнять 1 на 1 вместо параллели, и они будут блокировать поток пользовательского интерфейса при этом, даже если я попробуйте указать TaskCreationOptions.LongRunning.

Это никогда не происходит с моим первым вызовом Task.Factory.StartNew, это происходит только с последующими вызовами с первого обратного вызова.

Ответ 1

Чтобы принудительно запустить новый поток, вы должны указать TaskScheduler.Default в вызове Task.Factory.StartNew следующим образом:

Task.Factory.StartNew(action,
                      CancellationToken.None,
                      TaskCreationOptions.None,
                      TaskScheduler.Default).ContinueWith(completeAction);

В моем тестировании вам не нужно указывать TaskCreationOptions.LongRunning, чтобы заставить фоновый поток, хотя это не должно повредить.