C#多线程基本使用和探讨

线程是并发编程的基础概念之一。在现代应用程序中,我们通常需要执行多个任务并行处理,以提高性能。C# 提供了多种并发编程工具,如ThreadTask、异步编程和Parallel等。

Thread 类

Thread 类是最基本的线程实现方法。使用Thread类,我们可以创建并管理独立的线程来执行任务。

基本使用Thread 

创建一个新的实例对象,将一个方法直接给Thread类,并使用实例对象启动线程运行。

   static void Test() {
         Console.WriteLine("Test事件开始执行");
            Thread.Sleep(1000);
            Console.WriteLine("Test事件睡眠之后打印数据");
            Console.WriteLine("Test事件id: " + Thread.CurrentThread.ManagedThreadId);
       
        }
        static void Main(string[] args)
        {

            #region //主线程id
            Console.WriteLine("主线程id: " + Thread.CurrentThread.ManagedThreadId);
            #endregion

            #region //传递一个方法给线程,执行方法

            Thread t = new Thread(Test);
            t.Start();
            
            #endregion
}

线程数据传输

传递单个参数

Thread 提供了一个 Start(object parameter) 方法,可以在启动线程时传递一个参数。


        static int Downlod(object obj) {
            string str = obj as string;

            Console.WriteLine(str);
        }


     static void Main(string[] args)
        {

      Thread t1 = new Thread(Downlod);
           //这里传递的参数是字符串
            t1.Start("数据传递方法执行 ,数据传递方法id: "+Thread.CurrentThread.ManagedThreadId);

}

这种方式适用于需要传递单个参数的情况。

使用类的实例方法传递多个参数

先new一个类的实例,给实例字段赋值,调用类的实例,通过实例调用方法,构造函数接收参数,然后在线程中调用该实例的方法。

     static void Main(string[] args)
        {
// 使用 DownloadTool 实例化并传递数据
DownloadTool downloadTool = new DownloadTool("www.baidu.com", "这是下载链接哦");
Thread thread = new Thread(downloadTool.Download);
thread.Start();
}



public class DownloadTool
{
    private string url;
    private string message;

    public DownloadTool(string url, string message)
    {
        this.url = url;
        this.message = message;
    }

    public void Download()
    {
        Console.WriteLine("下载链接: " + url);
        Console.WriteLine("提示信息: " + message);
        Console.WriteLine("Download 线程 ID: " + Thread.CurrentThread.ManagedThreadId);
    }
}

thread 线程启动时,它会执行 downloadTool.Download() 方法,输出传递的数据。

线程优先级 

在 C# 中,可以使用 Thread.Priority 属性来设置线程的优先级。线程优先级决定了操作系统在多线程环境中调度线程的顺序,但并不保证高优先级的线程总是比低优先级的线程更早或更频繁地执行。

线程优先级级别

C# 提供了五个线程优先级级别,定义在 ThreadPriority 枚举中:

  1. Lowest:最低优先级。操作系统尽可能少地调度这个优先级的线程。
  2. BelowNormal:低于正常的优先级。优先级比 Normal 低,但高于 Lowest。
  3. Normal:默认优先级,大多数线程默认的优先级。适用于一般用途。
  4. AboveNormal:高于正常的优先级。操作系统更倾向于调度这个优先级的线程。
  5. Highest:最高优先级。操作系统尽可能多地调度这个优先级的线程。
  internal class Program
    {
     

        static void A()
        {
            int i = 0;
            while (true)
            {

                i++;
                Console.WriteLine($"A 输出第{i}");
                Thread.Sleep(1000);

            }
        }

        static void B()
        {
            int i = 0;
            while (true)
            {
                i++;
                Console.WriteLine($"B 输出第{i}");
                Thread.Sleep(1000);
            }
        }
        static void Main(string[] args)
        {
            //在C#中,线程的优先级可以通过Thread.Priority属性来设置和获取。
//        Lowest: 线程的优先级是最低的。在系统中存在其他活动线程时,此优先级的线程很少得到执行。
//BelowNormal: 线程的优先级低于正常线程。
//Normal: 线程的优先级是普通的,这是线程的默认优先级。
//AboveNormal: 线程的优先级高于正常线程。
//Highest: 线程的优先级是最高的。此优先级的线程会尽量优先于其他所有优先级的线程执行。
            Thread a = new Thread(A);
            Thread b = new Thread(B);
            a.Priority = ThreadPriority.Highest;
            a.Start();
            b.Priority = ThreadPriority.Lowest;
            b.Start();

            Console.WriteLine("按任意键停止线程...");
            Console.ReadKey();

        

            a.Join();
            b.Join();
            Console.WriteLine("线程已停止");

        }
    }
  • A 被设置为最高优先级 ThreadPriority.Highest
  • B 被设置为最低优先级 ThreadPriority.Lowest

注意事项

  1. 优先级不是绝对控制:操作系统可能会忽略优先级设置,特别是在资源有限的系统中。高优先级线程不一定会一直执行,也不能阻止低优先级线程的执行。

  2. 使用优先级的适用场景:设置线程优先级可能适用于实时系统(例如,某些任务需要优先处理)。但是,大多数应用程序通常可以使用默认的 Normal 优先级。

  3. 避免使用过多的高优先级线程:如果所有线程都被设置为 Highest,系统的整体性能可能会下降,甚至导致线程争用 CPU 资源的情况。

  4. CPU 密集型任务:在 CPU 密集型任务中,优先级可能会对性能产生较大影响,因为优先级高的线程可能会占用更多的 CPU 时间。

线程优先级的最佳实践

  • 默认使用 Normal 优先级,除非有特殊原因。
  • 避免滥用 Highest 优先级,因为它会对系统资源产生影响。
  • 在 I/O 密集型的线程中,优先级通常不会有显著差异,因为这些线程在等待 I/O 操作完成时,CPU 会调度其他线程。

通过合理设置线程优先级,可以帮助操作系统更好地调度线程,以满足应用程序的需求。 但通常在 .NET 应用程序中,多数情况下使用默认的 Normal 优先级就足够了。

线程池

线程池 (ThreadPool) 是一种高效的管理和调度线程的方式。线程池自动管理线程的创建、重用和销毁,从而减少了手动创建和管理线程的开销。

为什么使用线程池

  1. 性能更高:线程池会重用现有的线程,减少了创建和销毁线程的开销。
  2. 自动管理:线程池会根据系统负载动态调整线程数量。
  3. 避免线程资源不足:线程池限制了同时运行的线程数,避免了线程过多导致的资源耗尽问题。

基本使用 ThreadPool.QueueUserWorkItem 方法将任务排入线程池队列。

using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        // 将任务排入线程池
        ThreadPool.QueueUserWorkItem(DoWork, "任务 1");
        ThreadPool.QueueUserWorkItem(DoWork, "任务 2");

        Console.WriteLine("主线程完成");
        Thread.Sleep(3000); // 等待线程池中的任务完成
    }

    static void DoWork(object state)
    {
        string taskName = (string)state;
        Console.WriteLine($"{taskName} 开始执行 - 线程ID: {Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1000); // 模拟耗时操作
        Console.WriteLine($"{taskName} 执行完成 - 线程ID: {Thread.CurrentThread.ManagedThreadId}");
    }
}

运行结果QueueUserWorkItem自动分配线程来执行任务。

QueueUserWorkItem 方法将任务排入线程池。它接收一个委托(即方法)和一个可选的状态对象(传递给方法的数据)。

DoWork 方法接受一个参数 state,这是从 QueueUserWorkItem 传递的。

Thread.Sleep(3000) 确保主线程不会立即退出,使得线程池中的任务有机会完成。

使用带返回值的线程池任务

C# 中的 ThreadPool 通常不直接支持返回值。如果需要获得任务结果,可以使用 Task,因为 Task 本质上也是线程池的一部分。Task 更适合于带返回值的异步操作。这里使用 Task.Run 来代替 ThreadPool

     static void Main(string[] args)
        {

  //使用tesk多线程
           int a= Task.Run(() =>
            {
     
              int a =  Dowload();
                return a;
            }).Result;

            Task<int> task = Task<int>.Run(()=>{
             int a =   Dowload();
             
                return a;
            });
            //初始化一个CancellationTokenSource实例
            CancellationTokenSource source = new CancellationTokenSource();
            //task.Start();
            task.Wait(1000);
            source.Cancel();
        int result  =    task.Result;
            Console.WriteLine(result);
            
            Console.WriteLine($"tesk返回值{a}");
}

        static int  Dowload() {

            int a = 0;
            for (int i = 0; i < 10; i++)
            {
              a=  a + i + 1;
            }
         int?  id= Task.CurrentId;
            Console.WriteLine("Current thread ID: " + id);
            return a;


        
        }

线程池的限制

  • 任务运行时间过长:线程池中的线程本质上是共享资源,如果某个任务运行时间太长,将会占用线程池中的线程,导致其他任务无法及时执行。
  • 不适合实时系统:线程池中的任务调度是由系统管理的,无法保证精确的实时性。
  • 有限的线程数量:在高并发场景中,如果线程池中的线程全部被占用,新的任务将会等待,直到有线程可用。
线程池总结

线程池是一种高效的并发处理方式,适合于大多数轻量级的后台任务。在现代 C# 编程中,建议使用 Taskasync/await 进行异步操作,因为它们能简化代码,并且使用底层的线程池来管理线程。如果需要精确控制线程的执行,通常建议使用手动管理的 Thread 等。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888560.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

快递查询软件:实现单号识别与批量物流查询的高效工具

随着网络购物的普及&#xff0c;快递物流行业迎来了前所未有的发展机遇&#xff0c;同时也面临着巨大的挑战。跟踪物流信息成为一个难题&#xff0c;因此&#xff0c;快递查询软件的核心功能之一便是单号识别。传统的快递单号输入方式繁琐且易出错在此背景下&#xff0c;快递查…

代码随想录day22:回溯part4

491.递增子序列 class Solution {List<List<Integer>> result new ArrayList<>();List<Integer> path new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}priv…

如何基于 RLHF 来优化 ChatGPT 类型的大语言模型

&#x1f6b4;前言 对于ChatGPT来说&#xff0c;RLHF是其训练的核心。所谓RLHF&#xff0c;即Reinforcement Learning with Human Feedback&#xff0c;基于人类反馈的强化学习。这项技术通过结合模型自身的生成能力和人类专家的反馈&#xff0c;为改进文本生成质量提供了新的…

计算机网络-------重传、TCP流量控制、拥塞控制

重传、滑动窗口、流量控制、拥塞避免 重传机制 超时重传 发送方在发送数据时会启动一个定时器&#xff0c;当超过指定的时间之后&#xff0c;还没接收到接收方的ACK确认应答报文&#xff0c;就会重传该数据 快重传 当发送方收到接收方三个连续的ack之后说明发送方发送的报…

关于Amazon Linux 2023的版本及包管理器

在亚马逊上创建EC2实例时&#xff0c;会看到有一个Amazon Linux镜像。 那这个镜像与其他Linux有什么关系和区别呢&#xff1f; 网站是介绍&#xff1a;Amazon Linux 2023 是基于 Linux 的现代化通用操作系统&#xff0c;提供 5 年的长期支持。它针对 AWS 进行了优化&#xff0…

《Linux从小白到高手》理论篇:深入理解Linux的计划任务/定时任务

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。本篇详细深入介绍Linux的计划任务/定时计划。 Linux的计划任务 在很多时候为了自动化管理系统&#xff0c;我们都会用到计划任务&#xff0c;比如关机&#xff0c;重启&#xff0c;备份之类…

详解Java中的BIO、NIO、AIO

1、 详解Java中的BIO、AIO、NIO 1.1、引言 IO流是Java中比较难理解的一个知识点&#xff0c;但是IO流在实际的开发场景中经常会使用到&#xff0c;比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO&#xff1a;BIO、NIO以及AIO&#xff0c;重点介绍NIO。…

读数据工程之道:设计和构建健壮的数据系统03数据工程生命周期(上)

1. 数据工程生命周期 1.1. 数据领域正在经历新数据技术和实践的爆炸式增长&#xff0c;抽象程度和易用性不断提高 1.2. 由于技术抽象程度的增加&#xff0c;数据工程师将越来越多地成为数据生命周期工程师&#xff0c;根据数据生命周期管理的原则来进行思考和操作 1.3. 数据…

专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结

目录 搜索 vs 深度优先遍历 vs 深度优先搜索 vs 宽度优先遍历 vs 宽度优先搜索 vs 暴搜 1.深度优先遍历 vs 深度优先搜索(dfs) 2.宽度优先遍历 vs 宽度优先搜索(bfs) 2.关系图暴力枚举一遍所有的情况 3.拓展搜索问题全排列 决策树 1. 计算布尔⼆叉树的值&#xff08;medi…

yub‘s Algorithmic Adventures_Day7

环形链表 link&#xff1a;https://leetcode.cn/problems/linked-list-cycle-ii/description/ 思路分析 我只能说双指针yyds【刻板hh】 我们分两种情况来分析 起码在第二圈才会相遇 fast比slow多走环的整数倍 fast 走的步数是 slow 步数的 2 倍&#xff0c;即 f2s&#xff…

计算机的错误计算(一百一十七)

摘要 算式“(5^25*(1/25)^(1/5)*3^25(1/25)^(1/5)*5^25*3^(251/5)-(9/25)^(1/5)*3^25*5^25-(1/25)^(1/5)*3^25*5.0^25*(13^(1/5)-3^(2/5.0)))” 的准确值是0. 但是&#xff0c;Python 与 Excel 均输出了错误结果&#xff1a;一个含有15位整数&#xff0c;一个含有14位整数。 …

Python | Leetcode Python题解之第464题我能赢吗

题目&#xff1a; 题解&#xff1a; class Solution:def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:cachedef dfs(usedNumbers: int, currentTotal: int) -> bool:for i in range(maxChoosableInteger):if (usedNumbers >> i) & 1…

初学者如何快速入门人工智能

一、引言 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;&#xff0c;作为当今科技领域极具前景与影响力的方向之一&#xff0c;吸引着众多人士投身其中。无论是对科技充满好奇的学生&#xff0c;还是意图拓展职业发展路径的职场人士&#xff0c…

网络知识_001_浏览器输入域名

文章目录 网络模型IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;网络地址&#xff0c;广播地址&#xff0c;NAT转换浏览器输入域名到网页打开发生了什么DNS获取顺序 网络模型 模型协议工具报文添加信息作用应用层http&#xff0c;https&#xff0c;ftp&#xff0c;…

认识动态规划算法和实践(java)

前言 动态规划算法里面最有意思的一个东西之一。动态规划初学肯定会有一定晦涩难懂。如果我们去网上搜索&#xff0c;动态规划的资料&#xff0c;它一开始都是将很多的理论&#xff0c;导致会认为很难&#xff0c;但是这个东西实际上是有套路的。 动态规划的英语是Dynamic Pr…

Java爬虫技术:解锁1688商品搜索的新维度

Java爬虫技术简介 Java爬虫技术是指使用Java语言编写的程序&#xff0c;模拟浏览器行为&#xff0c;自动化地从互联网上获取信息。随着技术的发展&#xff0c;Java爬虫技术已经非常成熟&#xff0c;有多种框架和库可以使用&#xff0c;如Jsoup、HttpClient、WebMagic等。 1688…

【操作系统】引导(Boot)电脑的奇妙开机过程

&#x1f339;&#x1f60a;&#x1f339;博客主页&#xff1a;【Hello_shuoCSDN博客】 ✨操作系统详见 【操作系统专项】 ✨C语言知识详见&#xff1a;【C语言专项】 目录 什么是操作系统的引导&#xff1f; 操作系统的引导&#xff08;开机过程&#xff09; Windows操作系…

【2024最新】华为HCIE认证考试流程

HCIE是华为认证体系中最高级别的ICT技术认证&#xff0c;表示通过认证的人具有ICT领域专业知识和丰富实践经验。 HCIE认证方向&#xff1a;最高认证级别HCIE的技术方向有13个 下面以HCIE-Datacom为例给大家介绍一下&#xff1a; HCIE-Datacom认证考试流程&#xff1a; 1.笔试…

ecmascript标准

ECMAScript&#xff08;简称ES&#xff09;是由Ecma国际&#xff08;前身为欧洲计算机制造商协会&#xff0c;European Computer Manufacturers Association&#xff09;制定的一种标准化的脚本程序设计语言。它是JavaScript的核心&#xff0c;定义了语言的语法、类型、语句、关…

Stable Diffusion最新版nowebui的api使用详解

最近在使用stable diffusion最新版的Stable Diffusion WebUI Forge进行api调用,下面来一步一步的进行展开吧!!! 1、下载lllyasviel/stable-diffusion-webui-forge GitHub - lllyasviel/stable-diffusion-webui-forgeContribute to lllyasviel/stable-diffusion-webui-for…