Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何强制Task.Factory.StartNew到后台线程?_C#_.net 4.0_Task_Threadpool - Fatal编程技术网

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

C# 如何强制Task.Factory.StartNew到后台线程?,c#,.net-4.0,task,threadpool,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

我见过许多其他类似的问题,但没有找到我的答案

我的问题是,我正在使用以下流创建线程:

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);
}
private void btn\u单击(对象发送者,事件参数e)
{
service.GetCount(
(计数,ex)=>
{
如果(ex!=null)
返回;
for(int i=0;i
{
return client.GetCount();//同步方法,可能需要很长时间
};
操作完成操作=(任务)=>
{
异常ex=(task.Exception!=null)?task.Exception.InnerException:task.Exception;
if(回调!=null)
回调(task.Result,ex);
};
Task.Factory.StartNew(action).继续(completeAction,callingRead);
}
公共void Get(操作回调,int索引)
{
var callingThread=TaskScheduler.FromCurrentSynchronizationContext();
Func action=()=>
{
return client.Get(index);//同步方法,可能需要很长时间
};
操作完成操作=(任务)=>
{
异常ex=(task.Exception!=null)?task.Exception.InnerException:task.Exception;
if(回调!=null)
回调(task.Result,ex);
};
Task.Factory.StartNew(action).继续(completeAction,callingRead);
}
这样,我的每个服务的异步方法都将回调它们最初调用的线程(通常是UI线程)。因此,我正在模拟wait/async关键字的工作方式(我不能使用.NET4.5)

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


这在我第一次调用Task.Factory.StartNew时不会发生,它只会发生在第一次回调中的后续调用中。为了强制启动新线程,您应该指定TaskScheduler。在调用Task.Factory.StartNew时,默认值如下所示:

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

在我的测试中,您不需要指定TaskCreationOptions.LongRunning来强制执行后台线程,尽管这不会有什么坏处。

LongRunning
强制创建一个全新的非线程池线程。@Servy-它不强制任何操作,只是给调度程序一个提示。@Henkholtman理论上,是的,这是正确的。实际上,在当前的实现中,它会导致创建一个新线程。虽然我同意最好假设它可能不会运行,但您应该假设将任务标记为长时间运行,而实际上它不会运行,这将消耗额外的资源。在上述问题中列出的场景中,TaskCreationOptions.LongRunning不会强制新的后台线程。仅使用TaskScheduler.Default执行。@Servy引发此问题的原因是,如果任何人依赖此实现详细信息(以下任务将在与当前任务不同的线程上执行),则可能导致死锁(通常称为“自死锁”或“自等待死锁”)如果违反了该假设。可能重复的