多线程详细介绍

什么是进程线程:TT快三TT快三我 们 来看一下自己的任务管理器

  

这里的每一项都是一个进程,TT快三TT快三我 们 的发布的每一个应用程序都需要一个进程去运行,在一个进程内可以有多个线程去计算执行程序。TT快三TT快三我 们 看下面的图片:

  

TT快三TT快三我 们 可以看一下进程和线程的数量,很明显可以看出,线程和进程的关系。TT快三TT快三我 们 的每一个操作都需要一个线程来执行,鼠标的点击就需要线程去响应TT快三TT快三我 们 的操作。

现在TT快三TT快三我 们 不难理解,TT快三TT快三我 们 一个应用程序就代表一个进程,想让TT快三TT快三我 们 的程序高效的运行TT快三TT快三我 们 就可以启用多个线程去执行了,当然采用多线程的话有好处也是有代价的,好处合理的利用计资源了,但是线程过多了,TT快三你 的CPU利用率就加大了,也有可能导致电脑的卡死。

在TT快三TT快三我 们 的程序中线程的代表就是:Thread本篇文章TT快三TT快三我 们 就说一下线程。TT快三TT快三我 们 先了解一下同步异步。

同步:指的是在同一线程下执行,并且会等待结果执行完毕。

异步:不再同一个线程下执行,并且执行得顺序不可控,不会等待执行结果完毕。

TT快三TT快三我 们 先用委托来演示一下多线程,如果不怎么了解委托得可以看一下上一篇文章:

    DelegateMethod Method = () =>
            {
           Console.WriteLine($"TT快三我
的线程ID是:{Thread.CurrentThread.ManagedThreadId}");
            };
            Method.BeginInvoke(null, null);
            Method.Invoke();

本来想用上面的代码去先简单的演示一下,谁知道NetCore 的程序集提供了,但是平台目前还不支持。 TT快三TT快三我 们 可以私下使用NET 试一下。

使用Thread 演示

 

            Console.WriteLine($"*********************************TT快三我
是同步TT快三方法
 *******************************");

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine($"TT快三我
的线程ID是:{Thread.CurrentThread.ManagedThreadId}");
            }
            Console.WriteLine($"*********************************同步TT快三方法
结束 *******************************");

            Console.WriteLine($"*********************************TT快三我
是异步TT快三方法
 *******************************");
            for (int i = 0; i < 10; i++)
            {
                 Thread thread = new Thread(() => { Console.WriteLine($"TT快三我
的线程ID是:{Thread.CurrentThread.ManagedThreadId}"); });
                 thread.Start();
            }
            Console.WriteLine($"*********************************异步TT快三方法
结束 *******************************");
  
            Console.ReadKey();

执行结果:

   

上面的代码执行结果中TT快三TT快三我 们 可以看到:同步TT快三方法 是同一个线程来执行的,之上而下有序的执行,但是异步TT快三方法 启动了多个线程去执行的,并且线程是无序的。看到这样的情况TT快三TT快三我 们 就会知道如果TT快三我 启动了很多线程线程用完之后也是有回收的,回收之后同样会分配的,也就是说同一个操作中线程的ID 可能会多次出现的。

            Console.WriteLine($"*********************************异步启动线程数量计算  *******************************");
            List<int> ListInt = new List<int>();
            int Conut = 0;
            for (int i = 0; i < 2000; i++)
            {
                Thread thread = new Thread(() =>
                {
                    if (ListInt.Contains(Thread.CurrentThread.ManagedThreadId))
                    {
                        Conut++;
                        Console.WriteLine($"TT快三我
的重复的线程TT快三我
的 ID是:{Thread.CurrentThread.ManagedThreadId}  重复线程总数量:{Conut}");
                    }
                
                    ListInt.Add(Thread.CurrentThread.ManagedThreadId);
                });
                thread.Start();
            }
            Console.WriteLine($"*********************************异步启动线程数量计算结果:{ListInt.Count}  *******************************");

结果: 

  

上面的结果TT快三TT快三我 们 可以看到:线程回收再利用。其实thread线程的回收就是TT快三TT快三我 们 的GC来做的,这就是C# 的强大之处,自动TT快三帮助 TT快三TT快三我 们 回收了。需要注意的是这样使用线程TT快三TT快三我 们 的回收过程是比较慢的,这个回收速度是TT快三TT快三我 们 计算机性能决定的。

在上面的结果中TT快三TT快三我 们 可以看到TT快三TT快三我 们 总共申请了1996个线程,其中有881个线程是重复的,线程的申请和销毁是耗费很多性能的,接下来TT快三TT快三我 们 看一下线程池。

线程thread有哪些可操作的属性

CurrentContext

获取线程正在其中执行的当前上下文。

CurrentCulture

获取或设置当前线程的区域性。

CurrentPrinciple

获取或设置线程的当前负责人(对基于角色的安全性而言)。

CurrentThread

获取当前正在运行的线程。

CurrentUICulture

获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。

ExecutionContext

获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。

IsAlive

获取一个值,该值指示当前线程的执行状态。

IsBackground

获取或设置一个值,该值指示某个线程是否为后台线程。

IsThreadPoolThread

获取一个值,该值指示线程是否属于托管线程池。

ManagedThreadId

获取当前托管线程的唯一标识符。

Name

获取或设置线程的名称。

Priority

获取或设置一个值,该值指示线程的调度优先级。

ThreadState

获取一个值,该值包含当前线程的状态。

 

 线程池:ThreadPool

       ThreadPool:线程池中的线程都是后台线程IsBackground属性都是True.不会影响所有的前台线程,也就是说不会影响用户体验。每个线程都有默认的堆栈大小和优先级,位于多线程池中。 一旦线程池中的线程完成任务,它将返回到等待线程队列中,这时TT快三TT快三我 们 就可以利用这些闲置的线程。通过这种重复使用,应用程序可以避免产生为每个任务创建新线程的开销。在每一个进程中都只会有一个线程池

 

            //public static bool SetMaxThreads(int workerThreads, int completionPortThreads);
            //public static bool SetMinThreads(int workerThreads, int completionPortThreads);
            //workerThreads 工作线程数量  completionPortThreads I/O线程数量
            ThreadPool.SetMaxThreads(12,12);  
            ThreadPool.SetMinThreads(12, 12);

TT快三我 这里设置工作线程,I/O线程数量来源于TT快三我 得计算机核心数量,保持每个核心最大最小线程都启动一个。查看计算机处理器核心数量。

  

上面的设置是说TT快三我 在线程池中给准备了数量为12 的线程。TT快三你 可以申请最多12个线程,在使用完之后TT快三我 会立马进行自动的回收,回收之后的线程继续存放在线程池中等待使用。相比于 Thread线程池ThreadPool对于线程的回收更快,性能更好。

代码看一下性能:

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < 1000; i++)
            {
                Thread thread = new Thread(() =>
                {
                    Console.WriteLine($"*********************************TT快三我
是多线程ThreadTT快三方法
 *******************************");
                });
                thread.Start();
            }
            Console.WriteLine($"*********************************ThreadTT快三方法
结束  耗费时间 :{stopwatch.ElapsedMilliseconds}  *******************************");

            Console.WriteLine($"*********************************多线程ThreadPool启动  *******************************");

            Stopwatch stopwatch1 = new Stopwatch();
            stopwatch1.Start();
            for (int i = 0; i < 1000; i++)
            {
                    WaitCallback act = (t) =>
                    {
                        Console.WriteLine($"*********************************TT快三我
是多线程ThreadPoolTT快三方法
 *******************************");
                    };
                    ThreadPool.QueueUserWorkItem(act);
            }
            Console.WriteLine($"*********************************ThreadPoolTT快三方法
结束  耗费时间 :{stopwatch1.ElapsedMilliseconds}  *******************************");

结果:Thread

  

结果:ThreadPool

  

上面的两个TT快三方法 TT快三TT快三我 们 都只是输出一行字符,但是以1000次的来说看一下性能相差有多少。所以建议大家都使用线程池。

TT快三推荐 官方文档:https://docs.microsoft.com/zh-cn/dotnet/standard/threading/?view=netframework-4.7.2

线程池:Task

随着框架的发展TT快三TT快三我 们 有了Task 他也是基于ThreadPool来重新封装的。他的出现方便了TT快三TT快三我 们 对多线程的回调等待更好的操作。

TT快三推荐 一篇TT快三计划:https://zgjhp.com/lonelyxmas/p/9509298.html

并行计算的多线程 Parallel

Parallel 多线程,这个类似同步的,他是在Task的基础之上又一次的封装。假如说TT快三TT快三我 们 启动多个线程,她像其他的一样启动了很多的子线程去执行的,而是和当前线程一样并行去执行的。并且当前线程也参与执行。他会卡住线程,等到全部执行完毕后才会继续

这个操作上不如Task 灵活,比如Task 可以等待其中一个线程执行完成后继续主线程,Parallel 是必须等待全部执行完毕。

Parallel里面大致分为三个TT快三方法 : For,ForEach,Invoke

Invoke:

            Console.WriteLine($"*********************************TT快三我
是主线程线程 ID:{Thread.CurrentThread.ManagedThreadId} *******************************");
            Action act = () => {

                Console.WriteLine($"TT快三我
的线程ID是:{Thread.CurrentThread.ManagedThreadId}");
            };
            Parallel.Invoke(act, act, act, act, act);

结果:

  

上面结果中TT快三TT快三我 们 可以看到主线程参与了进来。

ForEach:

        List<int> vs = new List<int>() { 1, 2, 3, 4, 5 };
            Parallel.ForEach<int>(vs, t =>
            {
                Console.WriteLine($"*********************************TT快三我
是  {t} *******************************");
            });

结果:

  

For

       List<int> vs = new List<int>() { 1, 2, 3, 4, 5 };
            //从零开始 循环多少次
            Parallel.For(0, vs.Count,t=> {
                Console.WriteLine($"*********************************TT快三我
是  {t} *******************************");
            });

结果:

  

上面的代码中TT快三TT快三我 们 可以看到Parallel 适合在TT快三TT快三我 们 循环的时候去使用这样并行的去执行,TT快三TT快三我 们 可以减少程序的执行时间。

如果当TT快三TT快三我 们 需要执行的集合过大有可能会 并行很多线程时TT快三TT快三我 们 怕会影响TT快三TT快三我 们 计算机的I/O TT快三TT快三我 们 还可以设置最大的并行数防止程序执行时i/o风暴

       //设置 Parallel 最大并行线程的数量
            ParallelOptions options = new ParallelOptions();
            //最大并行数为10;
            options.MaxDegreeOfParallelism = 10;

Parallel 官方介绍:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.parallel?redirectedfrom=MSDN&view=netframework-4.7.2

获取当前计算机 最大线程数

        int workerThreads;
            int completionPortThreads;
            ThreadPool.GetMaxThreads( out workerThreads, out completionPortThreads);
            Console.WriteLine($"最大工作线程:{workerThreads} 最大I/O线程:{completionPortThreads} ");

            ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
            Console.WriteLine($"最小工作线程:{workerThreads} 最小 I/O线程:{completionPortThreads} ");

结果:

  

有不足之处 希望大家指出相互学习,

            转载请注明出处 谢谢!

 

posted @ 2019-04-15 18:35 乐途 阅读(...) 评论(...) 编辑 收藏