C#学习(十三)——多线程与异步

一、什么是线程

程序执行的最小单元
一次页面的渲染、一次点击事件的触发、一次数据库的访问、一次登录操作都可以看作是一个一个的进程

在一个进程中同时启用多个线程并行操作,就叫做多线程
由CPU来自动处理
线程有运行、阻塞、就绪三态

代码示例:

class Program
{
   
    static void Main(string[] args)
    {
   
        Thread thread = new Thread(() =>
        {
   
            Print1();
        });

        thread.Start();

        for(int i = 0; i < 1000; i++)
        {
   
            Console.Write(0);
        }

        Console.Read();
    }
    
    static void Print1()
    {
   
        for (int i = 0;i < 1000; i++)
        {
   
            Console.Write(1);
        }
    }

}

运行结果为
示例代码运行结果
可以看到,在结果中,0和1的输出是交织在一起的,原因为两个线程交替着被运行,不断反复直到结束。
另外一个常用操作为Sleep();让时间暂停,使得线程进入静默状态。

二、前台线程、后台线程与线程池托管

代码举例:

class Program
{
   
    static void Main(string[] args)
    {
   
        Thread thread = new Thread(PrintHello);
        thread.Start();
        Console.WriteLine("退出主程序");
    }

    private static void PrintHello(object? obj)
    {
   
        while (true)
        {
   
            Thread.Sleep(1000);
            Console.WriteLine("Hello from PrintHello!");
        }
    }
}

运行会发现,即使主线程运行结束了,子线程依旧在持续运行;持续运行的子线程就称为前台线程
一般来说,只有等待前台线程运行完毕后,程序才可以进行关闭。
与之对应的是 后台线程,可以通过thread.IsBackground = true;//切换为后台线程将前台 线程切换到后台线程,这样再次运行会发现,当主线程结束后,后台线程就会被强制结束。

一般来说,前台线程用于需要时间比较长的等待业务,比如监听客户端请求,而后台线程适用于时较短的业务比如执行客户端发来的请求,后台进程不会影响程序的终止。
托管在线程池中的线程全部为后台线程
所有使用new Thread创建的线程默认均为前台线程

三、线程池

示例代码

for(int i = 0;i < 100; i++)
{
   
    ThreadPool.QueueUserWorkItem((o) =>
    {
   
        Console.WriteLine($"循环次数{
     i} 线程id {
     Thread.CurrentThread.ManagedThreadId}");
    });
}

线程池执行结果
可以看到执行结果出现了id重复的状况,原因就是线程池会重复使用已经完成的线程,极大节约硬件资源。
另外,可以看到,for循环有100次,但是从输出结果来看,只执行了十几次,原因为线程池创建的线程均为后台线程,只要主程序退出,线程池的后台线程就会被停止,而主程序main执行的时间很短,因此线程池内线程没有来得及执行就被停止了。

对于重要的并发量小的线程,需要手动创建管理,对于并发量大而又不太重要的线程,最好托管到线程池中。

四、结束线程与CancellationToken

不管程序有多少个进程,进程内部的资源都是被共享的。所以C#对进程的取消代码作了更高层次的抽象,把进程的取消过程封装成为了Token的形式,也就是CancellationToken(取消令牌)。不仅可以使用在多线程中,还可以用于异步操作。

class Program
{
   
    static void Main(string[] args)
    {
   
        CancellationTokenSource cts = new CancellationTokenSource();

        Thread thread = new Thread(() => {
    PrintHello(cts.Token); });
        thread.Start();

        //下载文件
        Thread.Sleep(5000);

        //关闭子进程
        //cts.Cancel();
        cts.CancelAfter(
  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值