zoukankan      html  css  js  c++  java
  • 2019-1-29-C#-Task.Run-和-Task.Factory.StartNew-区别

    title author date CreateTime categories
    C# Task.Run 和 Task.Factory.StartNew 区别
    lindexi
    2019-01-29 16:14:52 +0800
    2018-06-16 16:22:49 +0800
    C#

    有小伙伴问我,为什么不推荐他使用 Task.Factory.StartNew ,因为 Task.Run 是比较新的方法。 本文告诉大家 Task.Run 和 Task.Factory.StartNew 区别

    有很多博客说到了 Task.Run 和 Task.Factory.StartNew 区别,所以我也就不需要展开告诉大家。

    只需要知道 Task.Run 是在 dotnet framework 4.5 之后才可以使用,但是 Task.Factory.StartNew 可以使用比 Task.Run 更多的参数,可以做到更多的定制。

    可以认为 Task.Run 是简化的 Task.Factory.StartNew 的使用,除了需要指定一个线程是长时间占用的,否则就使用 Task.Run

    创建新线程

    下面来告诉大家使用两个函数创建新的线程

                Task.Run(() =>
                {
                    var foo = 2;
                });

    这时 foo 的创建就在另一个线程,需要知道 Task.Run 用的是线程池,也就是不是调用这个函数就会一定创建一个新的线程,但是会在另一个线程运行。

                Task.Factory.StartNew(() =>
                {
                    var foo = 2;
                });

    可以看到,两个方法实际上是没有差别,但是Task.Run比较好看,所以推荐使用Task.Run

    等待线程

    创建的线程,如果需要等待线程执行完成在继续,那么可以使用 await 等待

            private static async void SeenereKousa()
            {
                Console.WriteLine("开始 线程"+Thread.CurrentThread.ManagedThreadId);
                await Task.Run(() =>
                {
                    Console.WriteLine("进入 线程" + Thread.CurrentThread.ManagedThreadId);
                });
                Console.WriteLine("退出 线程"+Thread.CurrentThread.ManagedThreadId);
            }

    但是需要说的是这里使用 await 主要是给函数调用的外面使用,上面代码在函数里面使用 await 函数是 void 那么和把代码放在 task 里面是相同

            private static async void SeenereKousa()
            {
                Console.WriteLine("开始 线程"+Thread.CurrentThread.ManagedThreadId);
                await Task.Run(() =>
                {
                    Console.WriteLine("进入 线程" + Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine("退出 线程"+Thread.CurrentThread.ManagedThreadId);
                });
            }

    但是如果把 void 修改为 Task ,那么等待线程才有用

    除了使用 await 等待,还可以使用 WaitAll 等待

                Console.WriteLine("开始 线程" + Thread.CurrentThread.ManagedThreadId);
                var t = Task.Run(() =>
                {
                    Console.WriteLine("进入 线程" + Thread.CurrentThread.ManagedThreadId);
                });
    
                Task.WaitAll(t);
    
                Console.WriteLine("退出 线程" + Thread.CurrentThread.ManagedThreadId);

    使用 WaitAll 是在调用 WaitAll 的线程等待,也就是先在线程 1 运行,然后异步到 线程2 运行,这时线程1 等待线程2运行完成再继续,所以输出

    开始 线程1
    进入 线程2
    退出 线程1

    长时间运行

    两个函数最大的不同在于 Task.Factory.StartNew 可以设置线程是长时间运行,这时线程池就不会等待这个线程回收

                Task.Factory.StartNew(() =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        var foo = 2;
                    }
                    Console.WriteLine("进行 线程" + Thread.CurrentThread.ManagedThreadId);
                }, TaskCreationOptions.LongRunning);

    所以在需要设置线程是长时间运行的才需要使用 Task.Factory.StartNew 不然就使用 Task.Run

    调用 Task.Run(foo) 就和使用下面代码一样

    Task.Factory.StartNew(foo, 
        CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

    实际上 Task.Run(foo) 可以认为是对 Task.Factory.StartNew 封装,使用简单的默认的参数。如果需要自己定义很多参数,就请使用 Task.Factory.StartNew 定义参数。

    博客园博客只做备份,博客发布就不再更新,如果想看最新博客,请到 https://blog.lindexi.com/

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我[联系](mailto:lindexi_gd@163.com)。
  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/lindexi/p/12086479.html
Copyright © 2011-2022 走看看