Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.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.New vs Task.Run vs async/await是不阻塞UI线程的最佳方式_C# - Fatal编程技术网

C# Task.Factory.New vs Task.Run vs async/await是不阻塞UI线程的最佳方式

C# Task.Factory.New vs Task.Run vs async/await是不阻塞UI线程的最佳方式,c#,C#,我需要确保我的一些代码在后台运行,并且不会阻止UI线程,我认为我知道如何使用Task.Factory.New,但是随着我阅读的越来越多,它似乎并不总是创建一个新线程,但如果线程池认为这是一种方法,它有时会在UI线程上运行它,所以现在我很困惑该使用什么来确保安全,该方法不会阻塞UI线程。我还应该补充一点,我不需要该方法的返回值,我只需要它异步运行(在后台) 那么,下面这些方法之间的区别是什么?最好使用什么来确保它不会阻塞UI线程 Task.Factory.StartNew并不总是创建一个在后台运行

我需要确保我的一些代码在后台运行,并且不会阻止UI线程,我认为我知道如何使用Task.Factory.New,但是随着我阅读的越来越多,它似乎并不总是创建一个新线程,但如果线程池认为这是一种方法,它有时会在UI线程上运行它,所以现在我很困惑该使用什么来确保安全,该方法不会阻塞UI线程。我还应该补充一点,我不需要该方法的返回值,我只需要它异步运行(在后台)

那么,下面这些方法之间的区别是什么?最好使用什么来确保它不会阻塞UI线程

Task.Factory.StartNew并不总是创建一个在后台运行且不阻塞UI的线程,这是真的吗

     public Form1()
    {
        Task.Factory.StartNew(() => Thread.Sleep(1000));

        Task.Run(() => Thread.Sleep(1000));

        Task<int> longRunningTask = LongRunningOperationAsync();
    }

    public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
    {
        await Task.Delay(1000);
        return 1;
    }
public Form1()
{
Task.Factory.StartNew(()=>Thread.Sleep(1000));
Task.Run(()=>Thread.Sleep(1000));
Task longRunningTask=LongRunningOperationAsync();
}
公共异步任务LongRunningOperationAsync()//假定此长时间运行的操作返回int
{
等待任务。延迟(1000);
返回1;
}

前两者实际上是相同的。看

你可以把它看作是一项你想完成的任务。 线程类似于为您执行任务的工作者。因此,线程基本上可以帮助您完成任务,但它不会返回值

任务不会创建自己的操作系统线程。相反,任务由TaskScheduler执行;默认调度程序仅在线程池上运行

一个例子是。远程请求可以作为任务执行,您希望任务完成,但不知道何时完成。但是服务器的TCPListener我会作为线程运行,因为它总是需要监听套接字


正如Andreas Niedermir指出的,您也可以将长寿任务与
任务创建选项一起使用。您给出的两个示例几乎相同,并且取决于您使用它们的上下文

任务是一种用元信息描述工作包的方法,用于了解其状态、同步多个任务、取消任务等。关于任务和异步性的主要思想是,您不必关心此工作单元的“执行位置”(在哪个线程上),它是异步执行的,这就是您需要知道的全部内容。因此,用户界面线程不用担心,只要异步工作,它就不会被锁定(这是自Win8和async/await关键字以来的主要改进之一,每个用户界面操作都必须是异步的,以避免用户界面膨胀)

至于async&await,它们实际上是语法糖。在许多简单的情况下,您不需要关心任务本身,您只需要异步计算“这样做,并在有答案时给我答案”

int x=await computexanc()//返回将自动展开为int的任务
如果需要同步任务,例如并行启动多个任务并等待所有任务完成后再继续,则不能依赖简单的
wait Task
格式,然后需要使用任务本身、其
Status
属性以及在本例中的
Task.WaitAll(Task[])
API

编辑:我真的推荐JonSkeets书C#Depth(上一版)的章节。Async/Await部分解释得很好,它比任何在线阅读都要深入

我还应该补充一点,我不需要该方法的返回值

注意一个常见问题:不需要返回值并不意味着不应该等待返回的任务<代码>等待
等待任务也会为您提供异常信息。忽略返回的任务唯一合适的时间是当您不关心返回值您不关心后台工作可能引发的任何异常时(也就是说,您可以默默地接受它们)

在超过99%的情况下,适当的行为是等待任务

那么下面这些方法的区别是什么呢

StartNew
是在线程池线程上运行代码的过时方法。我在我的博客上详细描述了原因,但简短的回答是,
StartNew
不理解
async
委托,并且有不适当的默认选项

async
完全不同
Run
在线程池线程上执行代码,但
async
重写代码,以便在执行异步操作时不需要线程。因此,
Run
示例将在
thread.Sleep
调用中阻塞线程池线程1000ms。
async
示例将在UI线程上运行,然后在
wait Task.Delay
调用中在1000毫秒内不使用UI线程

最好使用什么来确保它不会阻塞UI线程

根据后台代码的性质,
Task.Run
async
都适用于UI应用程序

如果您的代码是异步的(通常是所有I/O绑定的代码),那么您应该使用
async
/
wait
。请注意,“自上而下”强制异步是很困难的。不要考虑“将代码从UI线程中强制删除”;相反,确定系统的自然异步部分(DB、文件、WebAPI调用等),在最低级别将它们更改为
async
,然后从那里开始工作

如果您的代码是同步的(CPU受限),那么如果在UI线程上运行时间过长,则可以使用
Task.Run

Task.Factory.StartNew并不总是创建一个在后台运行且不阻塞UI的线程,这是真的吗

     public Form1()
    {
        Task.Factory.StartNew(() => Thread.Sleep(1000));

        Task.Run(() => Thread.Sleep(1000));

        Task<int> longRunningTask = LongRunningOperationAsync();
    }

    public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
    {
        await Task.Delay(1000);
        return 1;
    }
Run
始终执行代码