C# 异步多线程入门到精通之ThreadPool篇

上一篇:C# 异步多线程入门到精通之Thread篇
下一篇:异步多线程之入Task,待更新

启动线程池线程

ThreadPool 提供的 API 相对于 Thread 是比较少的,在 ThreadPool 中需使用 QueueUserWorkItem 方法,来启动一个线程

例如:Dosome 是个普通的方法,传入 QueueUserWorkItem 方法开启新线程执行此方法

public static void Dosome()
{
    Console.WriteLine($"Task Start ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
}

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    ThreadPool.QueueUserWorkItem(x => Dosome());

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

启动线程,可以看到新开启了一个子线程 3 执行任务,而主线程 1 并没有等待子线程 3

线程池线程数量

在 1.0 时代的 Thread 是没有线程数量概念的,在 ThreadPool 2.0 时代,线程池线程数量可以通过 SetMaxThreads、SetMaxThreads 方法设置最小最大线程。也可以查看线程池线程数量,以通过 GetMinThreads、GetMaxThreads 方法获取线程池最小及最大线程数量。

注意:一般不建议设置 ThreadPool 线程数量,这个操作是全局的。二般情况,当线程池线程耗尽,会造成死锁。

例如:以通过 SetMaxThreads、SetMaxThreads、GetMinThreads、GetMaxThreads 方法来操作查看线程

{
    ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin);//工作线程,io线程
    Console.WriteLine($"【default】最小 workerThreadsMin:{workerThreadsMin}  completionPortThreadsMin:{completionPortThreadsMin}");

    ThreadPool.GetMaxThreads(out int workerThreadsMax, out int completionPortThreadsMax);//工作线程,io线程
    Console.WriteLine($"【default】最大 workerThreadsMax:{workerThreadsMax}  completionPortThreadsMax:{completionPortThreadsMax}");
}

ThreadPool.SetMinThreads(3, 3); // 设置4其实也不是4,应为本机为逻辑八核,最小也就是这个
ThreadPool.SetMaxThreads(7, 7);

{
    ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin);//工作线程,io线程
    Console.WriteLine($"【自定义】最小 workerThreadsMin:{workerThreadsMin}  completionPortThreadsMin:{completionPortThreadsMin}");

    ThreadPool.GetMaxThreads(out int workerThreadsMax, out int completionPortThreadsMax);//工作线程,io线程
    Console.WriteLine($"【自定义】最大 workerThreadsMax:{workerThreadsMax}   completionPortThreadsMax:{completionPortThreadsMax}");
}

ThreadPool.SetMinThreads(5, 5); // 设置4其实也不是4,应为本机为逻辑八核,最小也就是这个
ThreadPool.SetMaxThreads(16, 16);

{
    ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin);//工作线程,io线程
    Console.WriteLine($"【自定义】最小 workerThreadsMin:{workerThreadsMin}  completionPortThreadsMin:{completionPortThreadsMin}");

    ThreadPool.GetMaxThreads(out int workerThreadsMax, out int completionPortThreadsMax);//工作线程,io线程
    Console.WriteLine($"【自定义】最大 workerThreadsMax:{workerThreadsMax}   completionPortThreadsMax:{completionPortThreadsMax}");
}

线程池线程等待

看了前面 ThreadPool 相关的讲解,有小伙伴可能会发现,我们一直没有说等待线程,那 ThreadPool 有相关的 API 吗?答案:没有

但可以通过 ManualResetEvent 方式实现线程等待。一般来说不建议线程等待,二般情况也不建议。应为线程池里面,线程数量有限,写代码无意间造成的线程等待没有释放,一旦线程池线程耗尽就会形成死锁。除非非得等待情况,但记得一定要释放等待,多多检查代码。

例如:线程等待,ManualResetEvent 初始化为 false,Set() 方法会设置为 true,WaitOne() 方法会检查 ManualResetEvent 对象是否为 true,如果不为会一直等待,如果为 true 会直接过去

public static void Dosome()
{
    Console.WriteLine($"Task Start ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
    Thread.Sleep(5 * 1000); // 模拟任务耗时
    Console.WriteLine($"Task End ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
}

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    ManualResetEvent manualResetEvent = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(x =>
    {
        Dosome();
        manualResetEvent.Set(); // 会变成 true
    });
    manualResetEvent.WaitOne();

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

启动程序,可以看到主线程 1 等待 子线程 3 执行完成后,在执行了 Main 方法结束代码

例如:线程耗尽形成死锁,首先对线程池线程数量进行了限制,最大为 10 个线程。接着我们循环启动 18 个线程工作,且让前 18 个线程形成等待。

 Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

 ThreadPool.SetMinThreads(4, 4);
 ThreadPool.SetMaxThreads(10, 10);
 ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin);//工作线程,io线程
 Console.WriteLine($"【自定义】最小 workerThreadsMin:{workerThreadsMin}  completionPortThreadsMin:{completionPortThreadsMin}");
 ThreadPool.GetMaxThreads(out int workerThreadsMax, out int completionPortThreadsMax);//工作线程,io线程
 Console.WriteLine($"【自定义】最大 workerThreadsMax:{workerThreadsMax}   completionPortThreadsMax:{completionPortThreadsMax}");

 ManualResetEvent manualResetEvent = new ManualResetEvent(false);
 for (int i = 0; i < 20; i++)
 {
     int k = i;
     ThreadPool.QueueUserWorkItem((x) =>
     {
         Console.WriteLine(k);
         if (k < 18)
         {
             manualResetEvent.WaitOne();
         }
         else
         {
             manualResetEvent.Set();
         }
     });
 }
 manualResetEvent.WaitOne();

 Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

 Console.ReadLine();

启动程序,可以看到,当开启 10 个线程后,程序就已经不再运行了。这是当程循环开启第 11 个子线程时,发现线程池里面没有线程了,就会一直等待,这样一个状态就是死锁。

线程回调

讲到现在,细心的小伙伴会发现一直没有说线程回调,即当子线程执行一个任务完成后,再执行一个任务。其实 Thread 与 ThreadPool 都没有回调,但是可以创造出 Callback,那就是包一层,如果不行那就再包一层。

Thread

例如:创建一个普通方法 ThreadWithCallback 传入两个委托参数,一个实际任务,一个 Callback。接着在内部使用 Thread 开启一个新的线程,执行 action、callback 方法。

private static void ThreadWithCallback(Action action, Action callback)
{
    Thread thread = new Thread(() =>
    {
        action.Invoke();
        callback.Invoke();
    });
    thread.Start();
}

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    ThreadWithCallback(() =>
    {
        Console.WriteLine($"action,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
    }, () =>
    {
        Console.WriteLine($"callback,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
    });

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

启动程序,可以看到 action 执行后,再执行了 callback

ThreadPool

例如:创建一个普通方法 ThreadWithCallback 传入两个委托参数,一个实际任务,一个 Callback。接着在内部使用 ThreadPool 开启一个新的线程,执行 action、callback 方法。

private static void ThreadWithCallback(Action action, Action callback)
{
    ThreadPool.QueueUserWorkItem(x =>
    {
        action.Invoke();
        callback.Invoke();
    });
}

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    ThreadWithCallback(() =>
    {
        Console.WriteLine($"action,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
    }, () =>
    {
        Console.WriteLine($"callback,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");
    });

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

启动程序,可以看到 action 执行后,再执行了 callback

线程返回值

讲到现在,细心的小伙伴会发现一直没有说线程返回值,在 1.0、2.0 时代的 Thread、ThreadPool 是没有提供相关 API 的。但是可以创造出来,还是包一层,如果不行那就再包一层。

Thread

例如:创建一个普通方法 ThreadWithReturnCallback 返回与入参都是 Func< T >,内部启用一个 Thread 执行委托,return 一个带返回值的委托且 Thread 的线程等待放置里面。使用时给 ThreadWithReturnCallback 方法传入带返回值的委托即可,因为 ThreadWithReturnCallback 方法返回值也是委托,所以要想获得结果需要在外部 Invoke 一下,这个 Invoke 操作会卡主线程。

private static Func<T> ThreadWithReturnCallback<T>(Func<T> func)
{
    T t = default(T);
    Thread thread = new Thread(() =>
    {
        t = func.Invoke();
    });
    thread.Start();

    return () =>
    {
        thread.Join();
        return t;
    };
}

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Func<int> func = ThreadWithReturnCallback<int>(() =>
    {
        return DateTime.Now.Millisecond;
    });

    int iResult = func.Invoke();
    Console.WriteLine(iResult);

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

ThreadPool

例如:创建一个普通方法 ThreadPoolWithReturnCallback 返回与入参都是 Func< T >,使用 QueueUserWorkItem 方法启动线程执行委托,因为 ThreadPool 本身并未提供线程等待方法,所以这里使用 ManualResetEvent 进行线程等待,return 一个带返回值的委托且 ManualResetEvent WaitOne 线程等待放置里面。使用时给 ThreadPoolWithReturnCallback 方法传入带返回值的委托即可,因为 ThreadPoolWithReturnCallback 方法返回值也是委托,所以要想获得结果需要在外部 Invoke 一下,这个 Invoke 操作会卡主线程。

private static Func<T> ThreadPoolWithReturnCallback <T>(Func<T> func)
{
    T t = default(T);

    ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    ThreadPool.QueueUserWorkItem(x =>
    {
        t = func.Invoke();
        manualResetEvent.Set(); // 会变成 true
    });

    return () =>
    {
        manualResetEvent.WaitOne();
        return t;
    };
}

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Func<int> func = ThreadPoolWithReturnCallback <int>(() =>
    {
        return DateTime.Now.Millisecond;
    });

    int iResult = func.Invoke();
    Console.WriteLine(iResult);

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

线程池线程重用

在 1.0 时代的 Thread 每次创建实例都会向操作系统申请线程,2.0 时代的 ThreadPool 每次使用 QueueUserWorkItem 都会向线程池拿取线程,并不会向操作系统申请线程。所以,使用 ThreadPool 创建线程的效率是高于 Thread 的。

例如:我们开启三波线程执行任务,执行相同的任务

static void Main(string[] args)
{
    Console.WriteLine($"Main 方法开始,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}\n");

    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"张三,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"李四,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"王五,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"麻溜,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });

    Thread.Sleep(1000);Console.WriteLine();

    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"张三,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"李四,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"王五,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"麻溜,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });

    Thread.Sleep(1000); Console.WriteLine();

    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"张三,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"李四,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"王五,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}"); });
    ThreadPool.QueueUserWorkItem(t => { Console.WriteLine($"麻溜,任务处理完成。ThreadId:{Thread.CurrentThread.ManagedThreadId}\n"); });

    Thread.Sleep(1000);

    Console.WriteLine($"Main 方法结束,ThreadId:{Thread.CurrentThread.ManagedThreadId},DateTime:{DateTime.Now.ToLongTimeString()}");

    Console.ReadLine();
}

启动程序,第一波的时候启用了 3、4、6、7,第二波重用了第一波的 6、7、第三波重用了第一、第二波的 3、4、5、8。其中未重用的呢,是线程并未回收(回收需要时间),所以未重用。

扩展知识-委托线程

委托的 BeginInvoke 方法使用的是线程池的线程,在任务执行完成后,子线程时不会被立马回收的,除非调用 EndInvoke 可以立马结束子线程回到线程池,利于线程更好的重用。

例如:BeginInvoke 线程不能立马被回收重用

static void Main(string[] args)
{
    Action<int> action = x =>
    {
        Console.WriteLine($"我是 {x},Thread:{Thread.CurrentThread.ManagedThreadId}");
    };

    for (int i = 0; i < 5; i++)
    {
        action.BeginInvoke(i,null,null);
    }

    Console.ReadLine();
}

启动线程,并发五次,分别启用了4、5、7、8、9,五个线程

例如:EndInvoke 线程更好重用,BeginInvoke 方法的第二个参数

static void Main(string[] args)
{
    Action<int> action = x =>
    {
        Console.WriteLine($"我是 {x},Thread:{Thread.CurrentThread.ManagedThreadId}");
    };

    for (int i = 0; i < 5; i++)
    {
        action.BeginInvoke(i, e => { action.EndInvoke(e); }, null);
    }

    Console.ReadLine();
}

启程序,可以看到并发 5 次只使用了,线程 3 与 8。

到此这篇关于C# 异步多线程入门到精通之ThreadPool篇的文章就介绍到这了,更多相关C# ThreadPool内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C# 异步多线程入门到精通之Thread篇

    上一篇:C# 异步多线程入门基础 下一篇:C# 异步多线程入门到精通之ThreadPool篇 Thread API 这里对 Thread 的一些常用 API 进行介绍,使用一些案例进行说明.由于 Thread 的不可控与效率问题,Thread 现在已经不常用了,这里介绍一些 API ,想更深入的同学可以继续研究研究. Instance 首先看 Thread 的构造函数,有 ThreadStart .ParameterizedThreadStart .maxStackSize 类型的参数,这三个常

  • c#中Winform实现多线程异步更新UI(进度及状态信息)

    引言 在进行Winform程序开发需要进行大量的数据的读写操作的时候,往往会需要一定的时间,然在这个时间段里面,界面ui得不到更新,导致在用户看来界面处于假死的状态,造成了不好的用户体验.所以在大量数据操作的应用上,需要使用多线程来处理这种情况.在c#中使用多线程很方便只需要使用System.Threading.Thread的一个实例的Start方法就行了,但是如何实现多线程之间的交互就不是那么简单.本文实现了用子线程去处理数据,并实时更新主线程的ui状态了.下面就开始一步步的去实现异步线程更新

  • C#多线程与异步的区别详解

    C#多线程与异步的区别详解 随着拥有多个硬线程 CPU(超线程.双核)的普及,多线程和异步操作等并发程序设计方法也受到了更多的关注和讨论.本文主要是想与各位高手一同探讨一下如何使用并发来最大化程序的性能. 多线程和异步操作的异同 多线程和异步操作两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性.甚至有些时候我们就认为多线程和异步操作是等同的概念.但是,多线程和异步操作还是有一些区别的.而这些区别造成了使用多线程和异步操作的时机的区别. 异步操作的本质 所有的程序最终都会由计算机硬件来

  • C#多线程ThreadPool线程池详解

    简单说明一下: 线程池可以看做容纳线程的容器:一个应用程序最多只能有一个线程池:ThreadPool静态类通过QueueUserWorkItem()方法将工作函数排入线程池: 每排入一个工作函数,就相当于请求创建一个线程: 线程池的作用: 1.线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率. 2.如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜.),况且我们还不能控制线程池中线程的开始.挂起.和

  • 解析C#多线程编程中异步多线程的实现及线程池的使用

    0.线程的本质 线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度. 1.多线程: 使用多个处理句柄同时对多个任务进行控制处理的一种技术.据博主的理解,多线程就是该应用的主线程任命其他多个线程去协助它完成需要的功能,并且主线程和协助线程是完全独立进行的.不知道这样说好不好理解,后面慢慢在使用中会有更加详细的讲解. 2.多线程的使用: (1)最简单.最原始的使用方法:Thread oGetArgThre

  • C# 异步多线程入门基础

    目录 进程.线程 1. 进程 2. 线程 分时.分片 同步.异步 异步.多线程 异步多线程效率 多线程无序性 扩展 异步多线程版本 下一篇:C# 异步多线程入门到精通之Thread篇 进程.线程 1. 进程 首先了解,什么是线程? 即一个应用程序运行时,占用资源的综合是一个进程.Windows 任务管理器里面可以看到,里面一个个都是在运行的进程. 2. 线程 线程是执行流的最小单位.线程其实是看不到的,其实也可以,例如 Windows 任务管理器:正在运行 272 个进程,272 个进程运行了

  • 深入分析C#中的异步和多线程

    许多开发人员对异步代码和多线程以及它们的工作原理和使用方法都有错误的认识.在这里,你将了解这两个概念之间的区别,并使用c#实现它们. 我:"服务员,这是我第一次来这家餐厅.通常需要4个小时才能拿到食物吗?" 服务员:"哦,是的,先生.这家餐厅的厨房里只有一个厨师." 我:"--只有一个厨师吗?" 服务员:"是的,先生,我们有好几个厨师,但每次只有一个在厨房工作." 我:"所以其他10个穿着厨师服站在厨房里的人--什么

  • C# ThreadPool之QueueUserWorkItem使用案例详解

    先看代码: //设置可以同时处于活动状态的线程池的请求数目. bool pool = ThreadPool.SetMaxThreads(8, 8); if (pool) { ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("参数1")); ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("参数2")); ThreadPool.Que

  • C# 异步多线程入门到精通之ThreadPool篇

    上一篇:C# 异步多线程入门到精通之Thread篇 下一篇:异步多线程之入Task,待更新 启动线程池线程 ThreadPool 提供的 API 相对于 Thread 是比较少的,在 ThreadPool 中需使用 QueueUserWorkItem 方法,来启动一个线程 例如:Dosome 是个普通的方法,传入 QueueUserWorkItem 方法开启新线程执行此方法 public static void Dosome() { Console.WriteLine($"Task Start

  • C#多线程之线程池ThreadPool用法

    目录 一.ThreadPool 1.QueueUserWorkItem() 2.GetMaxThreads() 3.GetMinThreads() 4.SetMaxThreads()和SetMinThreads() 二.线程等待 三.线程重用 一.ThreadPool ThreadPool是.Net Framework 2.0版本中出现的. ThreadPool出现的背景:Thread功能繁多,而且对线程数量没有管控,对于线程的开辟和销毁要消耗大量的资源.每次new一个THread都要重新开辟内

  • C#多线程之线程池ThreadPool详解

    一.ThreadPool概述 提供一个线程池,该线程池可用于执行任务.发送工作项.处理异步 I/O.代表其他线程等待以及处理计时器. 创建线程需要时间.如果有不同的小任务要完成,就可以事先创建许多线程/在应完成这些任务时发出请求.不需要自己创建这样一个列表.该列表由ThreadPool类托管. 这个类会在需要时增减池中线程的线程数,直到最大的线程数.池中的最大线程数是可配置的.在双核CPU中,默认设置为1023 个工作线程和1000个I/O线程.也可以指定在创建线程池时应立即启动的最小线程数,以

  • c# 异步编程入门

    一.什么算异步?   广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的.在面向服务的系统中,各个子系统之间通信一般都是异步的,例如,订单系统与支付系统之间的通信是异步的,又如,在现实生活中,你去馆子吃饭,工作流是这样的,点菜->下单->做你的事->上菜->吃饭,这个也是异步的,具体来讲你和厨师之间是异步的,异步是如此重要,因外它代表者高效率(两者或两者以上的工作可以同时进行),但复杂,同步的世界简单,但效率极极低. 二.在编程中的异步   在编程中,

  • Python多线程入门学习

    Python 中使用线程有两种方式:函数或者用类来包装线程对象. 函数式: 调用 thread 模块中的start_new_thread()函数来产生新线程. 语法如下: thread.start_new_thread(function, args[, kwargs]) 参数说明: function - 线程函数. args - 传递给线程函数的参数,它必须是个 tuple 类型. kwargs - 可选参数. import thread import time # 为线程定义一个函数 def

  • 详解C#异步多线程使用中的常见问题

    目录 异常处理 线程取消 临时变量 线程安全 异常处理 小伙伴有没有想过,多线程的异常怎么处理,同步方法内的异常处理,想必都非常非常熟悉了.那多线程是什么样的呢,接着我讲解多线程的异常处理 首先,我们定义个任务列表,当 11.12 次的时候,抛出一个异常,最外围使用 try catch 包一下 static void Main(string[] args) { Console.WriteLine($"Main Start,ThreadId:{Thread.CurrentThread.Manage

  • C#多线程之线程池(ThreadPool)

    一.简介 前面介绍了平时用到的大多数的多线程的例子,但在实际开发中使用的线程往往是大量的和更为复杂的,这时,每次都创建线程.启动线程.从性能上来讲,这样做并不理想(因为每使用一个线程就要创建一个,需要占用系统开销):从操作上来讲,每次都要启动,比较麻烦.为此引入的线程池的概念. 好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”. 在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.需要处理的

  • SpringBatch从入门到精通之StepScope作用域和用法详解

    目录 1.StepSope 是一种scope 2.StepSope 是一种自定义step 3.如何使用.@Value是支持spel表达式的 3.1 大部分场景是Spel 表达式.在底层reader/process/writer 中使用@Value获取jobParamter/stepContext/jobContext 3.2 SpEL引用bean 3.3 系统属性 3.4 运算符号 4.可能遇到问题 5.StepScope原理 6.自定义一个scope 1.StepSope 是一种scope 在

随机推荐