当前位置: 首页 > news >正文

C# 多线程编程核心要点:不只是Thread和lock

聊到C#多线程,很多人第一反应就是Threadlock。没错,它们是基石,但如果你只停留在它们,那就像只会用菜刀切菜,永远做不出满汉全席。现代C#多线程的核心思想是 “高效地利用计算资源,并安全地处理并发”。下面我跟你捋几个最核心的点,保证接地气。


1. 为什么要用多线程?—— “别让CPU看戏”

想象一下,你的程序需要从网上下载10个文件。如果用单线程,它就是傻乎乎地一个一个下,期间CPU大部分时间都在那“空转”(等待网络响应)。多线程的核心目的就是充分利用多核CPU的计算能力,把这种“等待”的时间利用起来,让其他线程去干活,或者把一个大任务拆成多个小任务同时处理,极大提升程序性能和响应速度。

  • CPU密集型:计算圆周率、图像处理、加密解密。开多个线程,让每个CPU核心都忙起来。
  • I/O密集型:读写文件、网络请求、数据库访问。开多个线程,在等待一个I/O操作时,让CPU去处理别的线程的任务。

2. 线程安全:最大的“坑”——“你的变量,大家的变量”

这是多线程最核心、最易出错的概念。多个线程同时访问同一个资源(变量、集合、文件等),如果不做任何保护,结果将是不可预知的。

// 一个经典的错误示例
private static int _counter = 0;void Main()
{for (int i = 0; i < 10; i++){// 启动10个线程,每个都对 _counter 加1000次new Thread(() => {for (int j = 0; j < 1000; j++)_counter++; // 这行不是原子操作!}).Start();}Thread.Sleep(2000);Console.WriteLine(_counter); // 你几乎永远得不到 10000!
}

为什么?因为 _counter++ 在底层其实是三步:读 -> 改 -> 写。线程A读完值(比如100)后,可能还没来得及写回,线程B也读了(也是100),然后两个线程都计算完写回,结果就成了101,而不是预期的102。

怎么办?加“锁”(Synchronization)

最常用的工具就是lock关键字(Monitor的语法糖)。

private static readonly object _lockObj = new object(); // 必须是一个私有、只读的引用对象
private static int _counter = 0;void Main()
{for (int i = 0; i < 10; i++){new Thread(() => {for (int j = 0; j < 1000; j++)lock(_lockObj) // 只有一个线程能进入这块代码{_counter++;}}).Start();}Thread.Sleep(2000);Console.WriteLine(_counter); // 现在稳稳的是 10000
}

记住:锁的对象应该是一个私有的、只读的引用类型对象,千万别用lock(this)lock(“string”)这种。


3. 现代多线程的利器:Task 和 async/await

别再一上来就new Thread()了!Thread是“底层工人”,创建和销毁成本高,不好管理。.NET 4.0 引入的 TPL(Task Parallel Library) 才是我们现在的主力。

  • Task:代表一个异步操作。它比Thread更轻量,底层用的是线程池,能高效地管理和复用线程,避免了频繁创建销毁线程的开销。

    // 用 Task 来执行后台计算
    Task.Run(() => {// 这里会在线程池线程中执行DoSomeHeavyCalculations();
    });
    
  • async/await(C# 5.0):这是异步编程的语法糖,它的主要目的是解放UI线程,保持界面响应,而不是直接创建新线程。

    // 在UI按钮点击事件中
    private async void btnDownload_Click(object sender, EventArgs e)
    {btnDownload.Enabled = false;// await 不会阻塞UI线程!// 它告诉编译器:等这个耗时的Task完成后再回来执行后面的代码,期间UI线程是自由的。string data = await HttpClient.GetStringAsync("http://example.com");// 这里会自动回到UI线程上下文,所以可以直接更新UItxtResult.Text = data;btnDownload.Enabled = true;
    }
    

    关键理解async/await本身不创建新线程。HttpClient.GetStringAsync这类I/O操作,大部分时间是在等待网络硬件,根本不需要占用任何CPU线程。它用了一种叫“IO完成端口”的高效机制。只有在遇到CPU密集型任务时,你才应该用Task.Run把它推到后台线程。


4. 并发集合:让你“锁”得更少一点

List<T>, Dictionary<TKey, TValue>这些集合都不是线程安全的。如果你每次都靠lock来保护它们,代码会很难写且容易死锁。

.NET 在 System.Collections.Concurrent 命名空间下提供了一堆现成的线程安全集合:

  • ConcurrentBag<T>: 一个无序的包,适合生产者-消费者场景。
  • ConcurrentDictionary<TKey, TValue>: 线程安全的字典,它的GetOrAdd, AddOrUpdate等方法非常强大且原子性。
  • BlockingCollection<T>: 一个带阻塞功能的集合,是实现生产者-消费者模式的绝佳工具。

用它们可以大大减少你手动lock的次数。


5. 取消操作:让线程“优雅地”退出

你不能直接粗暴地Abort()一个线程,这会导致资源泄露和状态不一致。正确的做法是使用协作式取消

.NET 提供了 CancellationTokenSourceCancellationToken 来实现这个模式。

void Main()
{var cts = new CancellationTokenSource();// 启动一个可取消的任务var task = Task.Run(() => DoWork(cts.Token), cts.Token);// 2秒后发出取消信号Thread.Sleep(2000);cts.Cancel();try { task.Wait(); } catch (AggregateException ex) { /* 处理取消异常 */ }
}void DoWork(CancellationToken token)
{while (true){token.ThrowIfCancellationRequested(); // 如果已取消,就抛出OperationCanceledException// ... 或者也可以这样检查if (token.IsCancellationRequested)break; // 优雅地清理并退出循环// 做一点工作Thread.Sleep(500);}
}

总结一下核心思想:

  1. 目的:榨干CPU性能,提升响应能力。
  2. 基石:理解线程安全,熟练使用lock
  3. 现代工具:抛弃原始的Thread,拥抱 Taskasync/await。分清 CPU密集型(用Task.Run)和 I/O密集型(用async/await)。
  4. 基础设施:使用并发集合减少锁的烦恼。
  5. 良好习惯:使用取消令牌实现优雅停止。

把这些点吃透,你就能解决95%的日常多线程问题了。剩下的就是一些高级主题,比如内存模型、信号量(SemaphoreSlim)、读写锁(ReaderWriterLockSlim)等,等遇到具体场景再深入研究也不迟。

相关文章:

C# 多线程编程核心要点:不只是Thread和lock

聊到C#多线程,很多人第一反应就是Thread和lock。没错,它们是基石,但如果你只停留在它们,那就像只会用菜刀切菜,永远做不出满汉全席。现代C#多线程的核心思想是 “高效地利用计算资源,并安全地处理并发”。下面我跟你捋几个最核心的点,保证接地气。1. 为什么要用多线程?…...

基于MATLAB的图像融合拼接GUI系统设计

一、GUI架构设计(基于App Designer) % 创建GUI组件 fig = uifigure(Name,图像融合拼接系统,Position,[100,100,800,600]);% 控件布局 btnLoad = uibutton(fig,Text,加载图像,Position,[20,500,100,30],...ButtonPushedFcn,@(btn,event) loadImageCallback());btnPreprocess =…...

Python使用多线程和异步调用

概述 在 Python 中,多线程和异步调用是处理并发任务的两种常用方式,适用于不同场景。 多线程(threading 模块) 多线程适合处理 I/O 密集型任务(如网络请求、文件读写),因为这类任务大部分时间在等待,线程可以在等待时切换到其他任务。 import threading import timedef…...

研究生学术英语读写教程(中国科学院大学出版) Unit10 TextA 原文以及翻译(仅供学习)

本文全程使用kimi助手识别原书文字并翻译,无人工校准,没有参考任何其他翻译文章,仅供学习使用,如有侵权请联系我,会及时删除。 The Doctors Dilemma: Is It Ever Good to Do Harm? 原文1 Medical knowledge changes swiftly, and technological changes make new and exp…...

基于Python+Vue开发的蛋糕商城管理系统源码+运行步骤

项目简介该项目是基于Python+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的蛋糕商城管理系统项目,大学生可以在实践中学习和…...

某运营商智慧协同平台——构建高效、敏捷的运营管理新模式

项目背景 在某运营商数字化运营战略的指引下,我司携手该运营商,共同打造智慧协同运营平台。该平台旨在实现省市协作,赋能一线,通过引入君南信息的技术和服务支持,提升业务支撑效率、加强系统安全防护、增强平台功能与服务,以满足全省21个地市独立配置、维护和管理数据展示…...

go使用反射获取http.Request参数到结构体 - 实践

go使用反射获取http.Request参数到结构体 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace …...

基于MATLAB/Simulink的TI2000系列DSP模型设计

一、开发环境配置工具安装安装MATLAB R2023a + Simulink 安装TI C2000 Support Package(通过Add-On Explorer) 安装Code Composer Studio (CCS) v7.5+硬件连接将TI2000系列DSP开发板(如C28069)通过USB连接至PC 在CCS中完成设备驱动配置二、模型设计流程 1. 创建Simulink模型…...

nginx 常用参数

...

Python常见函数和代码示例

内置函数 print() - 输出信息到控制台 name = "Alice" age = 30 print("姓名:", name, "年龄:", age) # 输出多个值 print(f"姓名: {name}, 年龄: {age}") # 使用f-string格式化输出 print("姓名: {}, 年龄: {}".format(na…...

69-SQLite应用 - 详解

69-SQLite应用 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14…...

mysql 源码下载,从获取到安装的完整指南

你是否曾想过亲手剖析MySQL这个影响了整个互联网时代的数据库?本文将带你一步步获取MySQL源码,让你不仅能安装使用,更能深入探索其内部机制。 MySQL作为最流行的开源关系型数据库之一,其发展历程堪称传奇。从最初的免费开源到被Oracle收购,MySQL始终保持着强大的生命力。它…...

docker中centos7配置

拉取centos7镜像: docker pull centos:7 启动容器: docker run -d -it --privileged --name=test centos:7 /usr/sbin/init 进入容器: docker exec -it test /bin/sh centos7安装: #设置时区 timedatectl set-timezone Asia/Shanghai #安装crontab服务 yum install -y rsy…...

centos7虚拟机下系统环境配置

​1. 网络配置 网卡: nmcli d 网络查看: ip addr 网络配置文件: /etc/sysconfig/network-scripts/ifcfg-enoXXX BOOTPROTO=static;IPADDR=;GATEWAY=;NETMASK=255.255.255.0;ONBOOT=yes 重启网络服务: systemctl restart network.service 或:service network restart 配置D…...

CefSharp高版本问题

​最近做一个PC端功能,打算用CefSharp+vue3来做,但在设置cookie时,出现了怎么也设置不上的问题。以前用CefSharp+vue2做过PC端,思路是差不多的。开始觉得是vue3哪里的设置问题,没找到,那就将cookie打印出来,打印出来是空的。那么问题就出在CefSharp上了,由于安装新的Ce…...

前缀和pre,如何求总和:pre(r) - pre(l)(1 = l = r = n),以及|pre(r) - pre(l)|

前缀和pre,如何求总和:pre(r) - pre(l)(1 <= l <= r <= n),以及|pre(r) - pre(l)|我们假设 pre[i]: 数组前i个数的之和,这就是前缀和 计算所有下标对 (1 <= l <= r <= n) pre[r] - pre[l] 之和 如果数据量是 n <= 1e5,直接两个for循环暴力求解的话,时…...

P11537 [NOISG 2023 Finals] Toxic Gene 题解

先考虑如果所有的 T 已被排除,剩下的位置怎么判断是 R 还是 S。 注意到每种细菌可以在样本中放入任意多个,容易想到经典的套路:将 \(8\) 个位置一起处理,第 \(i\) 个在样本中出现 \(2^{i-1}\) 次,再加入一个 T。若结果 \(\land 2^{i-1}=2^{i-1}\),则第 \(i\) 个对应的位置…...

keil5中stm32相关记录

在Keil 5中如何建立一个STM32项目_keil cmsis-CSDN博客 keil中怎么使用中文语言_keil怎么设置中文-CSDN博客 STM32入门开发-详解GPIO口的配置与控制方式(以LED灯为例) - 知乎...

centos7中mysql环境配置

​mysql源: rpm -ivh http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm yum install mysql-server mysql-client libmysqlclient-dev mysql-devel MySQL-python远程连接: GRANT ALL PRIVILEGES ON *.* TO root@% IDENTIFIED BY 123456 ; flush privileges; 记…...

centos7中php环境配置

​php7源: rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm yum -y install php72w php72w-cli php72w-fpm php72w-common php72w-devel php72w-embedded php72w-gd ph…...

Symfony学习笔记 - 利用Doctrine开发一个学生信息的增删查改

现在在学习Symfony,Doctrine作为官方重点推荐的数库库Bundle,必须要试试! 1、创建Symfony的Demo的Web应用 symfony new symfony_webapp --webapp 正确安装后,目录应该是这样的:如果你的目录仅仅只有config和vendor目录,那就表明你没有安装完整。原因是symfony时,需要从h…...

如何在Nginx服务器配置https以及强制跳转https

...

centos7中安装protobuf-c

​前言 设备服务与设备端通讯,设备服务使用Go构建,使用protobuf格式与设备端通讯,设备端采用stm32系列mcu,使用C语言开发,所以要生成protobuf C语言版协议库。步骤1.准备 yum -y install autoconf automake libtool yum -y install gcc gcc-c++2.安装protobuf protobuf版本…...

赞助NYU-Poly女性网络安全研讨会:推动行业多元发展

本文介绍Trail of Bits公司赞助纽约大学理工学院女性网络安全研讨会的举措,包括活动目标、技术工作坊内容、职业发展指导以及往期参与记录,旨在促进网络安全领域的性别多元化。我们正在赞助NYU-Poly女性网络安全研讨会 Dan Guido 2014年9月29日 会议, 教育, 赞助 网络安全是一…...

MyEMS:开源能源管理的探索与实践

在当今社会,能源的有效管理与优化利用已成为企业、公共机构乃至全社会关注的核心议题。随着物联网(IoT)和大数据技术的成熟,相应的软件工具应运而生,旨在为解决能源挑战提供技术方案。MyEMS便是这一领域中的一个代表性开源项目。 什么是MyEMS? MyEMS是一个专为能源管理设…...

实时内核中的调度程序节流

实时内核包含一个保护机制,它允许分配供实时任务使用的带宽。保护机制被称为实时调度程序节流。 实时节流机制的默认值定义实时任务可以使用 95% 的 CPU 时间。其余的 5% 将被视为非实时任务,例如在 SCHED_OTHER 和类似调度策略下运行的任务。务必要注意,如果单个实时任务占…...

配置Burp Suite与Proxifier抓取微信小程序流量

微信小程序抓包教程:Burp Suite + Proxifier 配置指南 .container { max-width: 800px; margin: 0 auto; padding: 24px 40px; background-color: rgba(255, 255, 255, 1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); border-radius: 8px } .chart-container { position: rel…...

我的ai 相关工具站

在AI技术席卷日常生活的今天,美容与时尚领域也迎来了革新。如果你正在犹豫是否换发型、尝试新发色,或想看看不同年龄或面部效果的自己,RightHair.ai就是你的理想选择。这款完全免费的在线AI工具不仅能让你上传照片试穿200+种发型和发色,还提供AI年龄滤镜、微笑滤镜、瘦脸滤…...

C#第十一章 023 024

类 是一种数据结构析构器的声明 和构造器类似 ~Student(){}这样静态构造器是给静态属性的在类里面的类可以说是成员类或者嵌套类...

MyEMS:赋能每一个组织,成为自己的能源管理专家

能源管理曾是一件“昂贵”的事情。它意味着动辄七位数的软件许可费、依赖外部专家的深度定制,以及被特定供应商“锁定”的长期合约。这无形中为众多企业,特别是中小型企业和机构,筑起了一道难以逾越的高墙。 然而,数字时代的真正精神是“赋能”与“ democratization”(民主…...

Vue开发微信公众号上传图片

​处理思路:从服务器获取微信配置参数,进行微信配置 选择本地图片,获取图片base64输出 将base64图片转化为文件上传 关键代码: 1.获取配置与选择本地图片输出import http from ./http import api from ./api import wx from "weixin-js-sdk"; export default {g…...

centos7中scrapy运行环境配置

最近根据需要,使用scrapy开发了一个爬虫应用,直接使用的python2,记录一下部署环境。 1.安装epel扩展源 yum -y install epel-release 2.安装pip yum -y install python-pip3.安装scrapy pip install scrapy 阿里云镜像:pip install scrapy -i http://mirrors.aliyun.com/py…...

flutter配置国内镜像

git clone -b master https://mirrors.tuna.tsinghua.edu.cn/git/flutter-sdk.git设定方式如下: export FLUTTER_STORAGE_BASE_URL="https://mirrors.tuna.tsinghua.edu.cn/flutter" export PUB_HOSTED_URL="https://mirrors.tuna.tsinghua.edu.cn/dart-pub&qu…...

微信小程序 live-player 无声音

由于微信公众号在播放直播视频,方案上视频存在严重的延时,而小程序有live-player,可以做为低延时解决方案,所以准备改用小程序重写原来功能。问题描述: 1.微信小程序使用live-player控件播放基于腾讯lvb平台直播服务直播,视频由本地客户端,拉取摄像头视频向直播平台推流…...

栈的妙用:如何优雅地处理括号匹配难题 (C语言版)

栈的妙用:如何优雅地处理括号匹配难题 (C语言版)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace…...

食品包装 AI 视觉检测技术:原理、优势与数据应用解析

一、食品行业包装质检的核心技术痛点 在食品行业现代化生产体系中,包装质检作为保障食品安全与品质的关键环节,面临多维度技术挑战,具体体现在以下方面: 1、检测效率与产线速度不匹配 现代化食品生产线(如饮料灌装线、零食包装线)已实现高速运转,部分产线每分钟可完成数…...

电流探头的常见应用场景

电流探头是一种用于测量电流的传感器,广泛应用于电子、电力、通信等多个领域,其常见测试场景主要包括以下几类: 一、电子设备研发与调试 在电子设备的设计、研发和故障排查阶段,电流探头是关键工具,主要用于: 电路工作电流监测:测量各类电子电路(如主板、模块、芯片)的…...

WebRTC编码过载检测与帧率适应机制分析报告

WebRTC编码过载检测与帧率适应机制分析报告 1. 概述 本报告基于WebRTC源码分析,详细阐述了编码过载检测机制及其触发的帧率降级算法。分析范围涵盖从编码时间测量到最终帧率调整的完整调用链。 2. 编码使用率计算机制 2.1 基本计算公式 位置: android/cmake/src/video/adaptat…...

PC桌面应用开发选择

要使用Web方式,基本有3种方案可供选择: cef electron nwjs 1.cef情况下,.NET可以很好的支持,是个不错的方案 2.electron、nwjs主要在nodejs环境下开发,也是个不错选择 最后采用cef做壳,浏览器方式,Vue做页面形式开发。写于 2020-08-12...

陈燕的项目启动笔记

现在已经把项目起来了。 启动过程如下:1. 拉代码这里的前端的代码是缺少的,需要跟人要一下 2. 后端的mysql创建CREATE DATABASE IF NOT EXISTS lth_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 3. sql也有一些问题,把错误的sql都删除 4. mysql -u root -p 1234…...

C++面试宝典八股文之什么是封装、继承、多态(附面试宝典八股文PDF)

一、C++面试宝典&八股文 PDF文档自取:https://pan.quark.cn/s/5d4c5050d512 二、什么是封装、继承、多态? 1.封装 概念:封装是将数据(属性)和操作数据的方法(行为)捆绑在一起,形成一个独立的单元(即类),并尽可能隐藏类的内部实现细节,只保留有限的接口与外部交…...

无需复杂正则:SLS 新脱敏函数让隐私保护更简单高效

AI 时代海量交互数据推动智能应用快速发展,但其中的个人隐私信息也带来严峻的安全挑战。数据脱敏已从可选项转变为企业合规经营的必需品。作者:孙玉梅 背景 AI 时代海量交互数据推动智能应用快速发展,但其中的个人隐私信息也带来严峻的安全挑战。数据脱敏已从可选项转变为企…...

DRAM、SRAM、NAND Flash、NOR Flash、EEPROM、MRAM存储器你分得清吗?

DRAM、SRAM、NAND Flash、NOR Flash、EEPROM、MRAM存储器,这些是计算机和电子设备中最核心的几种存储器技术。 首先,我们可以从两个最根本的特性来对它们进行初步区分:​​易失性 (Volatile)​​:断电后数据是否丢失。​​读写特性​​:是像内存一样可以​​按字节随机读写…...

【初赛】最短路 次短路 k短路 - Slayer

最短路、次短路、k短路算法总结与C++代码示例 一、最短路算法 1. Dijkstra算法(单源最短路,非负权图)适用场景:有向/无向图,边权非负,求单源最短路径 时间复杂度:O(m log n)( n 为顶点数,m 为边数,使用优先队列+邻接表)2. Bellman-Ford 算法(单源最短路,支持负权图…...

hyperv 管理的 ubuntu 虚拟机压缩磁盘

1. 删除所有检查点,必须全部删除2. 多次执行 fstrim 命令sudo fstrim -av /: 488 GiB (498240180224 bytes) trimmed on /dev/sda2sudo fstrim -av /: 122 MiB (126992384 bytes) trimmed on /dev/sda2sudo fstrim -av /: 0 B (0 bytes) trimmed on /dev/sda2直到出现 0 B (0 …...

PLC结构化文本设计模式——适配器模式(Adapter Pattern)

PLC Structured Text Design Patterns PLC结构化文本设计模式——适配器模式(Adapter Pattern) 介绍 适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起…...

【实战记录】使用 wp-cli 恢复/修改 WordPress 密码

内容概览:使用 wp-cli 修改 WordPress 密码 docker 常规操作(文件复制、执行 bash 等)也是好久没写博客了,突发奇想想在自己的 WordPress 站点写一篇博文。 然后我惊讶的发现,我忘记密码了,更糟糕的是,出于安全考虑,我启用了这个:汗流浃背了家人们(非常推荐各位安装一…...

Spring Boot 下 Druid 连接池:多维度优化打造卓越性能

大家好,我是凯哥Java 本文标签:Spring Boot、Druid连接池、数据库连接池优化、性能监控 本文聚焦 Spring Boot 中 Druid 连接池的极致优化,从基础环境搭建、核心参数调优、监控体系构建、安全增强、连接泄漏检测等多方面展开,给出详细策略与高级技巧,还提供避坑指南,助力…...

讨好型人格自救指南:重建健康自我与关系

讨好型人格自救指南:重建健康自我与关系<script src="https://cdn.tailwindcss.com"></script><script>tailwind.config = {theme: {extend: {colors: {primary: #B8860B,secondary: #DAA520,accent: #F4E4BC,neutral: #2C2C2C,base-100: #FEFDFB…...

vue3使用vue3-pdf-app预览pdf文档

引入第三方组件库npm i vue3-pdf-app@1.0.3vue3 创建组件<template><VuePdfApp :style="`width: ${viewerWidth}; height: ${viewerHeight};`":pdf="src" @pages-rendered="pagesRendered" :config="config"></VuePdf…...