首页 > 编程语言 >C#中的线程简介

C#中的线程简介

时间:2024-02-28 13:00:27浏览次数:18  
标签:Console CurrentThread Thread C# 简介 线程 WriteLine id

C#中的线程简介

为什么要使用线程

  1. 同一时间智能运行一个任务,长时间运行的任务独占整个计算机,造成其他程序无法响应。
  2. 如果程序有bug会造成整个机器停止工作,用户只好重启计算机,造成数据丢失。

于是,人们为操作系统引入了线程的概念。线程就是对CPU的虚拟化。一个线程就是一个逻辑上的CPU。物理上的CPU会按照调度执行每个线程上的指令。当一个线程出现问题时,也不会影响到其他的线程。
这样,整个操作系统就更加健壮、易于伸缩和安全了。在安装了多个CPU的机器上,计算机是可以真正的同时运行多个线程的,这由操作系统进行保证。

线程的代价

  1. 线程需要占用内存空间
  2. 线程切换也会增加额外的CUP计算时间
  3. 线程的创建和销毁需要消耗大量时间

.Net中使用线程的方法

  1. 定义两个方法模拟耗时的操作
public static void Work1()
{
     Console.WriteLine($"Work1 开始 id:{Thread.CurrentThread.ManagedThreadId}");
     for (int i = 0; i < 25; i++)
     {
         Console.WriteLine($"Work2 {i}");
         Thread.Sleep(10);
     }
     Console.WriteLine($"Work1 结束 id:{Thread.CurrentThread.ManagedThreadId}");
 }
 public static int Work2()
 {
     Console.WriteLine($"Work2 开始 id:{Thread.CurrentThread.ManagedThreadId}");
     int count = 0;
     for (int i = 0; i < 100; i++)
     {
         Console.WriteLine($"Work1 {i}");
         Thread.Sleep(10);
         count += 1;
     }
     Console.WriteLine($"Work2 结束 id:{Thread.CurrentThread.ManagedThreadId}");
     return count;
 }
  1. 使用Thread执行两个方法
public static void UseThread()
{
    Console.WriteLine($"UseThread 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    Thread thread1 = new(Work1);//创建一个线程
    thread1.Start();//启动线程

    Thread thread2 = new(() => Work2());//由于Work2有返回值,用一个Lambda表达式包装后传入
    thread2.Start();

    Console.WriteLine($"UseThread 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
  1. 为了减少创建和销毁线程的开销,可以使用ThreadPool(线程池),它可以复用线程,从而提高了效率。
public static void UseThreadPool()
{
    Console.WriteLine($"UseThreadPool 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    ThreadPool.QueueUserWorkItem(t => Work1());
    ThreadPool.QueueUserWorkItem(t => Work2());

    Console.WriteLine($"UseThreadPool 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
  1. 直接使用线程执行任务时,在处理任务结果获取、线程取消、多线程任务协调等场景时,显得非常笨拙。于是在线程池的基础上,.Net推出了Task
public static void UseTask()
{
    Console.WriteLine($"UseTask 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    Task task1 = new(Work1);
    task1.Start();

    Task task2 = new(() => Work2());
    task2.Start();

    //上面跟直接使用Thread类似
    //下面也可以用TaskFactory启动任务

    //Task.Factory.StartNew(Work1);
    //Task.Factory.StartNew(() => Work2());

    Console.WriteLine($"UseTask 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
  1. 以上看起来跟使用Thread没什么差别,下面我们来看看使用Task的便利之处
//等待任务执行完成
public static void UseTaskWait()
{
    Console.WriteLine($"UseTaskWait 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    var task1 = Task.Factory.StartNew(Work1);
    var task2 = Task.Factory.StartNew(() => Work2());

    //Task.WaitAll(task1,task2);//两个任务都执行完成后,才继续执行后面的代码
    Task.WaitAny(task1, task2);//两个任务任何一个完成,就继续执行后面的代码

    Console.WriteLine($"UseTaskWait 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}

//任务执行完成后执行ContinueWith内的代码,并获得了返回值
public static void UseTaskContinueWith()
{
    Console.WriteLine($"UseTaskContinueWith 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    Task.Run(Work1);

    //此方法会异步执行,ContinueWith中传入回调函数,用于处理Work2返回的结果
    Task.Run(Work2).ContinueWith(r =>
    {
        Console.WriteLine($"Work2 result {r.Result}");
    });

    Console.WriteLine($"UseTaskContinueWith 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}

//获取任务的执行结果
public static void UseTaskResult()
{
    Console.WriteLine($"UseTaskResult 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    var task2 = Task.Run(Work2);

    task2.Wait();//这里会阻塞,等待task2执行完毕
    Console.WriteLine($"task2's result:{task2.Result}");

    //或者直接这样写

    //var result = task2.Result;//这里会阻塞,等待task2执行完毕
    //Console.WriteLine($"task2's result:{result}");

    Console.WriteLine($"UseTaskResult 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}
  1. 为了使用更方便,.Net上引入了async/await关键字,于是我们可以这样使用
public static async void CallMethodAsync1()
{
    Console.WriteLine($"CallMethodAsync1 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    var result = await Task.Run(Work2);
    Console.WriteLine($"result:{result}");

    Console.WriteLine($"CallMethodAsync1 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}

如果任务本身就是异步的

public static Task<int> Work3()
{
    Console.WriteLine($"Work3 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    var result = Task.Run(() =>
    {
        int count = 0;
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine($"Work1 {i}");
            Thread.Sleep(10);
            count += 1;
        }
        return count;
    });
    Console.WriteLine($"Work3 结束 id:{Thread.CurrentThread.ManagedThreadId}");
    return result;
}
//可以这样调用,有同样的效果

public static async void CallMethodAsync2()
{
    Console.WriteLine($"CallMethodAsync2 开始 id:{Thread.CurrentThread.ManagedThreadId}");

    var result = await Work3();

    Console.WriteLine($"result:{result}");

    Console.WriteLine($"CallMethodAsync2 结束 id:{Thread.CurrentThread.ManagedThreadId}");
}

标签:Console,CurrentThread,Thread,C#,简介,线程,WriteLine,id
From: https://www.cnblogs.com/higleam/p/18039965

相关文章

  • duel prob/duel chall 随记
    CF1404C\(2300\)。离线,数据结构。区区\(2k3\),居然想了这么久,没救了。类别为/duelprob。可以先离线,\(r\)端点从小到大排序。并且\(a_i=i-a_i\),这样,若\(a_i<0\),永远不能删掉。在\(l\in[1,n]\)都不行。如果\(a_i\geq0\)时,前面不能删多少它才不能删呢?有\(i......
  • Vue 2x 系列之(一)简介
    Vue简介1.Vue是什么?一套用于构建用户界面的渐进式JavaScript框架。​ 构建用户界面:将拿到的数据通过某种办法变成用户可以看到的界面。​ 渐进式:从一个轻量而又小巧的核心库逐渐递进到使用各式各样的Vue插件库【Vue可以自底向上逐层的应用】2.谁开发的?React、Angular3.......
  • 掌握字符与字符串:C语言中的神奇函数解析(二)
    ✨✨欢迎大家来到贝蒂大讲堂✨✨......
  • c# winform 多线程
    ​  privateTaskSchedulermpr_ts_UIContext;    privatevoidbutton1_Click(objectsender,EventArgse)    {      progressBar1.Visible=true;      progressBar1.Value=0; //清空进度条      progress......
  • Rust的ToOwned特征:泛型版的Clone
    std::borrow::ToOwned是Rust标准库中的一个特征,用于从借用的数据中创建一个具有所有权的副本。它的作用和Clone是一样的,但是相比Clone,它支持泛型;也就是说我们可以将一个类型T“Clone”为另一个类型U。这对处理一些特殊的类型来说很有用。ToOwned的签名ToOwned提供了两个方法,其中......
  • 微软 官方 .net 组件 下载 directx组件 下载 viual c++ 组件 下载 官方 修复DLL方
    下载.NETFramework|免费官方下载(microsoft.com).NETFramework是仅适用于Windows版本的.NET,用于生成客户端和服务器应用程序。升级应用在VisualStudio中单击几下即可将应用从.NETFramework升级到最新的.NET。  DownloadDirectXEnd-UserRuntimefromO......
  • centos7环境用docker-compose部署mysql5.7集群,redis7.2.4,springboot项目
    文件目录结构关于每个配置项及docker-compose的安装,大家可以自己查mysql配置文件master---my.cnf[mysqld]server_id=1gtid-mode=ONenforce-gtid-consistency=1binlog-ignore-db=mysqllog-bin=mysql-binbinlog_cache_size=......
  • PCDN边缘计算盒子X86机顶盒路由器,边缘计算源头厂家代理加盟
    自主研发核心算法,跑量好,收益高!专注于大数据处理、云计算服务的科技创新型平台服务商,作为源头厂家,可根据客户需求提供边缘计算一站式解决方案:软硬件开发、CDN各大云厂商业务直签,业务成熟稳定,资源变现快。成本低,方案多,效率高。PCDN代理加盟,电话/微信:13540308877PCDN(PeertoPeer......
  • 基于FPGA的ECG信号滤波与心率计算verilog实现,包含testbench
    1.算法运行效果图预览 其RTL结构如下:  2.算法运行软件版本vivado2019.2  3.算法理论概述        心电图(ECG)是医学领域中常用的一种无创检测技术,用于记录和分析心脏的电活动。由于ECG信号微弱且易受到噪声干扰,因此在采集和处理过程中需要进行滤波以提取......
  • Nacos身份认证绕过漏洞解决
    一、备份1.1备份nacos停止nacos服务/web/nacos/bin/shutdown.shcd/webmvnacosnacosbak-202311281.2备份mysql数据mysqldump-uroot-p-A>/web/nacos-20231128.sql二、部署新版nacos2.1下载nacos安装包cd/webwgethttps://github.com/alibaba/nacos/releases/......