线程池和任务

简介:
  1. 线程池


  • 创建线程和销毁线程是一个昂贵的操作,要耗费大量的时间。由于操作系统必须调度可运行的线程并执行上线文切换,所以太多的线程还对性能不利。

    为了改善这个情况,clr包含了代码来管理他自己的线程池。

    线程池是你的应用程序能使用的线程集合。

    线程池内部会维护一个 操作请求队列。应用程序执行一个异步请求操作时,将一个记录项(entry)追加到线程池的队列中。线程池的代码从这个对立中

    提取记录项,将这个记录项派发(dispatch)给一个线程池线程。

    当线程池完成任务后,线程不会被销毁。相反,线程会回到线程池,在哪里进入空闲状态,等待相应另一个请求。由于线程不销毁自身,所以不在再产生额spacer.gif外的性能损失;

  1. 线程池基础

  2. 我们来演示以线程池的方式异步的调用一个方法 

    public static void MainThreadPool()
            {
                Console.WriteLine("主线程异步操作队列");
                ThreadPool.QueueUserWorkItem(ThreadProc);
    
                Console.WriteLine("主线程做其他工作");
                Thread.Sleep(1000);//模拟其他工作
                Console.WriteLine("主线程运行结束");
    
                Console.ReadLine();
            }        /// <summary>
            /// 与委托WaitCallback 签名相同的回掉方法 
            /// </summary>
            /// <param name="stateInfo">如果使用的是QueueUserWorkItem(WaitCallback callBack),该参数默认为null</param>
            static void ThreadProc(Object stateInfo)
            {
                Console.WriteLine("线程池工作线程执行回掉");
                Thread.Sleep(1000); //模拟其他工作
            }

    输出:

任务
  • 改造下上面的例子,在t1任务完成之后启动t2任务

  • 目前,我们的任务实例还没有返回值,他们都是运行一些不返回值的委托。正如开头将的,任务是可以有返回值的。通过使用Task<TResult>实例,其中TResult要替换为返回类型。

    public static void RunGetStartTaskResult()
            {            var t1 = Task.Factory.StartNew(() => GetTask1("ChengTian"));            //等待t1 完成            t1.Wait();            var t2 = Task.Factory.StartNew(() =>
                {                for (int i = 0; i < t1.Result.Count; i++)
                    {
                        Console.WriteLine(t1.Result[i]);
                    }
    
                });
    
                Console.WriteLine("结束");
                Console.ReadLine();
            }        public static List<char> GetTask1(string ss)
            {
                Thread.Sleep(1000);            return ss.ToList();
            }

    输出返回值 

  • 如果想中断task实例的执行,可以通过取消标记(Cancellation Token)

  • CancellationTokenSource 能够初始化取消的请求,而CancellationToken能够将这些请求传递给异步的操作。
  • task实例的执行取决于底层硬件和运行时可用的资源。因此,在您获取了有关task实例的任何信息后,这个状态可能会发生改变,因为task实例的状态也在同时发生改变。当task到达它的3种可能的最终之一时,它再也回不去之前的任何状态了,如图所示。

  • T初始状态:task实例有3种可能的初始状态,详细说明如图

  • 最终状态:接下来,task实例可以转换到running状态,并且最终转变到一个最终状态。

    如果task实例有关联的子任务,那么就不能认为这个task完成了,并且这个task将转变到WaitingForChildrenToComplete 状态。当task实例的子任务都完成后,这个Task将进入3种可能的最终状态之一。详细说明如下如图

  1. 很容易使用ThreadPoolQueueUserWorkItem方法发起一次异步的计算限制操作。但这个技术有许多限制。最大的问题是没有内置的机制 让你知道操作在什么时候完成,也没有机制在操作完成时得到返回值。为了克服这些限制(并解决其他一些问题),微软引入了任务的概念。

    通过using System.Threading.Tasks 命名空间中的类型来使用任务。

  2. 创建任务 

    public static void RunGetStartTask()
            {            //创建方式之一 :通过task的构造函数
                Task t1 = new Task(Task1);            //创建方式之二:通过task工厂调用StartNew 创建并并启用
                Task t2 = Task.Factory.StartNew(Task2);
    
                Console.WriteLine("t1任务Start之前状态:{0},t2任务状态:{1}", t1.Status, t2.Status);
                t1.Start();
                Console.WriteLine("t1任务Start之后状态:{0},t2任务状态:{1}", t1.Status, t2.Status);
                
                Task.WaitAll(t1, t2);
    
                Console.WriteLine("主线程执行完毕");
                Console.WriteLine("t1最终状态:{0},t2最终状态:{1}", t1.Status, t2.Status);
                Console.ReadLine();
            }        public static void Task1()
            {
                Thread.Sleep(1000);
                Console.WriteLine("运行task1");
            }        public static void Task2()
            {
                Thread.Sleep(2000);
                Console.WriteLine("运行task2");
            }

    输出

  3. 理解任务状态和生命周期   

  4. 取消任务

  5. public static void RunGetStartTaskCancel()
            {            var cts = new CancellationTokenSource();            var ct = cts.Token;            var sw = Stopwatch.StartNew();            var t1 = Task.Factory.StartNew(() => Task1Cancel(ct), ct);            var t2 = Task.Factory.StartNew(() => Task2Cancel(ct), ct);            //主线程模拟1秒
                Thread.Sleep(1000);
    
                cts.Cancel();            try
                {                if (!Task.WaitAll(new Task[] { t1, t2 }, 3000))
                    {
                        Console.WriteLine("Task1Cancel 和 Task2Cancel 超过了2秒完成.");
                        Console.WriteLine("t1状态" + t1.Status.ToString());
                        Console.WriteLine("t2状态" + t2.Status.ToString());
                        Console.ReadLine();
                    }
                    Console.ReadLine();
    
                }            catch (AggregateException ex)
                {                foreach (Exception innerException in ex.InnerExceptions)
                    {
                        Debug.WriteLine(innerException.ToString());
                        Console.WriteLine("异常消息:" + innerException.ToString());
                    }                if (t1.IsCanceled)
                    {
                        Console.WriteLine("t1 task 运行Task1Cancel 已取消");
                    }                if (t1.IsCanceled)
                    {
                        Console.WriteLine("t2 task 运行Task2Cancel 已取消");
                    }
    
                    Console.WriteLine("耗时" + sw.Elapsed.ToString());
                    Console.WriteLine("完成");
                    Console.ReadLine();
    
                }
            }        public static void Task1Cancel(CancellationToken ct)
            {
                ct.ThrowIfCancellationRequested();            var sw = Stopwatch.StartNew();
                Thread.Sleep(1000); 
    
                Console.WriteLine("运行task1");
                Console.WriteLine("task1:" + sw.Elapsed.ToString());
                ct.ThrowIfCancellationRequested();
            }        public static void Task2Cancel(CancellationToken ct)
            {
                ct.ThrowIfCancellationRequested();            var sw = Stopwatch.StartNew();
                Thread.Sleep(2000);
    
                Console.WriteLine("运行task2");
                Console.WriteLine("task2:" + sw.Elapsed.ToString());
            }

  6. 从任务获取返回值

  7. 通过延续串联任务 

  8. public static void RunGetStartTaskContinueWith()
            {            var t1 = Task.Factory.StartNew(() => GetTask1("ChengTian"));            var t2 = t1.ContinueWith(t =>
                {                for (int i = 0; i < t1.Result.Count; i++)
                    {
                        Console.WriteLine(t1.Result[i]);
                    }
    
                });
    
                Console.WriteLine("结束");
                Console.ReadLine();
            }

    可以在任何任务实例上调用ContinueWith方法,创建一个延续。 你也可以串联很多任务,然后等待最后一个任务(在这个实例中为t2)执行完成.  











本文转自xsster51CTO博客,原文链接:http://blog.51cto.com/12945177/1948523 ,如需转载请自行联系原作者










相关文章
|
存储 Java 数据库
如何处理线程池关闭时未完成的任务?
总之,处理线程池关闭时未完成的任务需要综合考虑多种因素,并根据实际情况选择合适的处理方式。通过合理的处理,可以最大程度地减少任务丢失和数据不一致等问题,确保系统的稳定运行和业务的顺利开展。
728 64
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
424 62
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
533 17
|
数据采集 Java 数据处理
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
760 0
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
350 12
|
缓存 负载均衡 Java
c++写高性能的任务流线程池(万字详解!)
本文介绍了一种高性能的任务流线程池设计,涵盖多种优化机制。首先介绍了Work Steal机制,通过任务偷窃提高资源利用率。接着讨论了优先级任务,使不同优先级的任务得到合理调度。然后提出了缓存机制,通过环形缓存队列提升程序负载能力。Local Thread机制则通过预先创建线程减少创建和销毁线程的开销。Lock Free机制进一步减少了锁的竞争。容量动态调整机制根据任务负载动态调整线程数量。批量处理机制提高了任务处理效率。此外,还介绍了负载均衡、避免等待、预测优化、减少复制等策略。最后,任务组的设计便于管理和复用多任务。整体设计旨在提升线程池的性能和稳定性。
447 5
|
存储 监控 Java
|
前端开发 JavaScript 大数据
React与Web Workers:开启前端多线程时代的钥匙——深入探索计算密集型任务的优化策略与最佳实践
【8月更文挑战第31天】随着Web应用复杂性的提升,单线程JavaScript已难以胜任高计算量任务。Web Workers通过多线程编程解决了这一问题,使耗时任务独立运行而不阻塞主线程。结合React的组件化与虚拟DOM优势,可将大数据处理等任务交由Web Workers完成,确保UI流畅。最佳实践包括定义清晰接口、加强错误处理及合理评估任务特性。这一结合不仅提升了用户体验,更为前端开发带来多线程时代的全新可能。
541 1
|
Java Linux
Java演进问题之1:1线程模型对于I/O密集型任务如何解决
Java演进问题之1:1线程模型对于I/O密集型任务如何解决
200 1
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
300 1

热门文章

最新文章