C#多线程--基本概念和使用方法

基本概念
进程(Process):是系统中的一个基本概念。一个正在运行的应用程序在操作系统中被视为一个进程,包含一个运行程序所需要的资源,进程可以包括一个和多个线程。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界。
线程(Thread):是 进程中的基本执行单元,是操作系统分配CPU时间的基本单位 ,在进程入口执行的第一个线程被视为这个进程的 主线程 。
优点:可以同时完成多个任务;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;可以随时停止任务;可以设置每个任务的优先级以优化程序性能。
缺点
  1、 内存占用 线程也是程序,所以线程需要占用内存,线程越多,占用内存也越多(每个线程都需要开辟堆栈空间,多线程时有时需要切换时间片)。
  2、 管理协调 多线程需要协调和管理,所以需要占用CPU时间以便跟踪线程,线程太多会导致控制太复杂。
  3、 资源共享 线程之间对共享资源的访问会相互影响,必须解决争用共享资源的问题。
使用方法
1、ThreadStart:在 .NetFromework 1.0 1.1 出现,功能强大但是响应并不灵敏、不好控制–因为线程资源是操作系统管理的

        public static void ThreadStartTest()
        {
            ThreadStart threadStart = () =>
            {
                Console.WriteLine($"This is Tread start*****当前线程{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is end start*****当前线程{Thread.CurrentThread.ManagedThreadId}");
            };
            Thread thread = new Thread(threadStart);
            thread.Start();
        }

2、ThreadPool(线程池):在.NetFromework 2.0出现,有线程可以复用,可以限制最大线程的数据量,但API太少,线程等待顺序控制特别弱

 public static void ThreadPoolTest()
        {
            WaitCallback Callback = o =>
            {
                Console.WriteLine($"This is Tread ThreadPool*****当前线程{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is end ThreadPool*****当前线程{Thread.CurrentThread.ManagedThreadId}");
            };
            ThreadPool.QueueUserWorkItem(Callback);
        }

3、 Parallel 可以启动多个线程,主线程也参与计算,可节约一个线程;

        public static void ParallelTest()
        {
            //可以通过ParallelOptions轻松控制最大并发数量
            ParallelOptions parallel = new ParallelOptions();
            parallel.MaxDegreeOfParallelism = 2;//控制并发数量
            Parallel.Invoke(parallel, () =>
            {
                Console.WriteLine($"This is  Parallel start1*****当前线程{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is Parallel end1 *****当前线程{Thread.CurrentThread.ManagedThreadId}");

            }, () =>
            {
                Console.WriteLine($"This is  Parallel start2*****当前线程{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is Parallel end2 *****当前线程{Thread.CurrentThread.ManagedThreadId}");

            }, () =>
            {
                Console.WriteLine($"This is  Parallel start3*****当前线程{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is Parallel end3 *****当前线程{Thread.CurrentThread.ManagedThreadId}");

            },
            () =>
            {
                Console.WriteLine($"This is  Parallel start4*****当前线程{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"This is Parallel end4 *****当前线程{Thread.CurrentThread.ManagedThreadId}");

            });
        }

4、Task的背后使用的线程池技术进行实现的,但是它的性能要优于Thread Pool,因为它的使用的不是线程池的全局队列,而是使用的本地队列,使线程之间的竞争减少。同时Task提供了丰富的API来管理线程控制。但是相对于前面的两种耗内存,Task依赖于CPU对于多核CPU性能远超前两者,单核的CPU三者的性能没有什么差别。简单用法如下:

        public static void TaskTestDetails()
        {
            Console.WriteLine($"***********异步方法 start {Thread.CurrentThread.ManagedThreadId}***********");
            Console.WriteLine("ELeven又接到一个私活儿...");
            Console.WriteLine("沟通大概需求和标准,谈妥价格...");
            Console.WriteLine("签合同,收取50%的费用");
            Console.WriteLine("需求分析-框架搭建-模块切分。。。");
            Console.WriteLine("数据库初步设计。。");
            Console.WriteLine("高级班挑选学员,组建开发团队");
            Console.WriteLine("开始干活!");

            List<Task> tasklist = new List<Task>();
            tasklist.Add(Task.Run(() => Coding("小明", "Portal")));
            tasklist.Add(Task.Run(() => Coding("小张", "Client")));
            tasklist.Add(Task.Run(() => Coding("小红", "WeChat")));
            tasklist.Add(Task.Run(() => Coding("小青", "Service")));
            tasklist.Add(Task.Run(() => Coding("小成", "SqlServer")));
            tasklist.Add(Task.Run(() => Coding("小芳", "WebApi")));
            //Task.WaitAny(tasklist.ToArray());
            阻塞当前线程,直到任意一个线程结束---主线程被阻塞,所以卡界面
            //Console.WriteLine("项目达到一个里程碑,收取20%的费用");
            //Task.WaitAll(tasklist.ToArray());
            阻塞当前线程,直到全部任务结束---主线程被阻塞,所以卡界面
            //Console.WriteLine("项目验收后交付,支付剩余的全部费用");
            TaskFactory taskFactory = new TaskFactory();
            //等着任一任务完成后,启动一个新的task来完成后续的动作
            taskFactory.ContinueWhenAny(tasklist.ToArray(), t =>
            {
                Console.WriteLine($"项目达到一个里程碑,收取20%的费用***{Thread.CurrentThread.ManagedThreadId}***");
            });
            //等着全部任务完成后,启动一个新的task来完成后续的动作
            taskFactory.ContinueWhenAll(tasklist.ToArray(), t =>
            {
                Console.WriteLine($"项目验收后交付,支付剩余的全部费用***{Thread.CurrentThread.ManagedThreadId}***");
            });
            //continue的后续线程,可能是新线程,也能是刚完成的线程,还有可能是同一个线程,不可能是主线程
            Console.WriteLine($"***********异步方法 end {Thread.CurrentThread.ManagedThreadId}***********");

        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值