并发编程实现
一、并行编程
1、Parallel 类
Parallel类是System.Threading.Tasks命名空间中的一个重要类,它提供数据并行和任务并行的高级抽象。
For和ForEach
Parallel类下的For和ForEach对应着普通的循环和遍历(普通的for和foreach),但执行时会尝试在多个线程上同时处理循环迭代。
//For
Parallel.For(0, 10, i =>
{Console.WriteLine($"我是:{i}。我的线程ID是:{Thread.CurrentThread.ManagedThreadId}");
});
//ForEach
List<string> items = new List<string> { "A", "B", "C", "D", "E" };
Parallel.ForEach(items, item =>
{Console.WriteLine($"我是:{item}。我的线程ID是:{Thread.CurrentThread.ManagedThreadId}");
});
与普通For输出后的区别(右为普通For循环),我们可以看到Parallel类下For输出的顺序不是递增的,这是因为它是在不同的线程中执行所导致的。
Invoke
尽可能并行执行提供的每个操作,即方法调用。
Action action1 = () => Console.WriteLine("你好");
Action action2 = () => Console.WriteLine("不好");
Parallel.Invoke(action1, action2);
2、PLINQ
PLINQ为Parallel LINQ的缩写,在LINQ中允许你利用多核处理器并行处理数据,PLINQ会自动将查询拆分成多个部分,并在多个线程上并行执行这些部分。
AsParallel()
将顺序的LINQ查询转换为并行的查询,允许利用多核处理器并行处理数据集合,从而加速查询的执行,当调用该方法时,LINQ查询会转换为PLINQ查询。
int[] data = Enumerable.Range(0, 100).ToArray();
var query =from i in data.AsParallel()where i%10==0select i;
并行度
在默认的情况下,PLINQ会使用计算机上所有的处理器,使用WithDegreeOfParallelism用于指定用于并行查询执行的处理器的最大数量,即同时执行的任务数量。
int[] data = Enumerable.Range(0, 100).ToArray();
var query =from i in data.AsParallel().WithDegreeOfParallelism(3)where i%10==0select i;
排序
默认情况下,PLINQ 不保证输出顺序与输入顺序一致。如果需要保持顺序,可以使用AsOrdered()方法,但是调用该方法时,PLINQ 将尝试在并行处理的同时保留元素的顺序,这也就意味着性能可能会下降。
int[] data = Enumerable.Range(0, 100).ToArray();
var query =from i in data.AsParallel().AsOrdered()where i%10==0select i;
ForAll()
用于并行地遍历查询结果集,并对每个元素执行一个指定的操作,并行执行,可以充分利用多核处理器的性能优势,加快处理速度,但并不保证操作的执行顺序与原始数据集中的顺序一致。
query.ForAll(res =>
{Console.WriteLine(res);
});
二、数据并发控制
1、lock(锁)
lock关键字用于确保当一个线程进入代码的临界区时,其他线程不会进入该临界区,这有助于防止多个线程同时访问同一资源,可能导致数据不一致以及数据被破坏的问题。(lock关键字通常与对象一起使用,该对象用作锁定的目标,通常称为“锁对象”。)
public class Account
{private Object thisLock = new Object();public void Withdraw(){// 这是一个临界区,只有一个线程可以进入 lock (thisLock){try{//模拟工作for (int i = 0; i < 5; i++){Console.WriteLine($"我是{i},我的线程ID:{Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(500);//模拟延迟}}finally{Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}被释放了");// 确保锁被释放,即使发生异常 }}}
}
当我们使用两个或者多个线程同时调用该方法时, 只会有一个线程拿到锁对象进入到临界区,其余的线程会形成阻塞态,一直等待该锁被释放然后进入到临界区(或者任务超时该线程摧毁)。
Account account = new Account();
//创建线程1任务
Task task1 = Task.Run(() => account.Withdraw());
//创建线程2任务
Task task2 = Task.Run(() => account.Withdraw());
//等待两个任务完成
Task.WaitAll(task1, task2);
2、Monitor类
Monitor类允许线程安全地访问共享资源,是System.Threading命名空间的一部分,并且提供了比lock更底层和更灵活的功能,防止多个线程同时访问某个代码段或资源导致数据不一致以及数据被破坏的问题。
public class Account
{private Object thisLock = new Object();public void Withdraw(){//获取锁Monitor.Enter(thisLock);try{for (int i = 0; i < 5; i++){Console.WriteLine($"我是{i},我的线程ID:{Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(500);}}finally{Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}被释放了");//释放锁Monitor.Exit(thisLock);// 确保锁被释放,即使发生异常 }}
}
注意:一个线程获取到了锁,那么其他线程就会形成阻塞态,如果该线程的任务完成之后,没有释放锁,那么后面的线程就一直处于阻塞态的状态,形成死锁。
TryEnter
指定毫秒内获取锁,如果获取到锁则返回true,如果没有获取到锁,则返回false,该方法通常配合一些逻辑执行,任务完成后同样需要Exit来释放锁,否则会造成死锁。
bool MonitorBool = Monitor.TryEnter(thisLock,5000);
3、ReaderWriterLockSlim类
它允许多个读取者同时访问资源,但在写入时则独占资源,即不允许其他读取者或写入者同时访问(读共享写独享)。
1、基本读写锁
读锁(EnterReadLock和ExitReadLock):当多个线程需要同时读取共享资源时,可以使用读锁。多个线程可以同时持有读锁,这意味着它们可以同时读取共享资源,但在此期间,任何线程都不能获得写锁。
写锁(EnterWriteLock和ExitWriteLock):当线程需要修改共享资源时,它必须获得写锁。在写锁被持有的期间,其他线程既不能获得读锁也不能获得写锁,确保共享资源的单独访问。
public class Account
{private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();private int sharedData = 0;//写操作public void WriteData(int value){//获取写入锁rwLock.EnterWriteLock();try{//执行写入sharedData = value;Thread.Sleep(2000);//模拟延迟}finally{Console.WriteLine($"{sharedData}写入完成,我的线程ID:{Thread.CurrentThread.ManagedThreadId}");//释放写入锁rwLock.ExitWriteLock();}}//读操作public int ReadData(){//获取读取锁rwLock.EnterReadLock();try{Thread.Sleep(2000);//模拟延迟return sharedData;}finally{Console.WriteLine($"读取完成,我的线程ID:{Thread.CurrentThread.ManagedThreadId}");//释放读取锁rwLock.ExitReadLock();}}
}
2、升级读写锁
升级读锁(EnterUpgradeableReadLock和ExitUpgradeableReadLock):当线程以可升级的方式获取读锁时,它表示该线程可能随后需要升级到写锁,在此期间,其他线程不能获得写锁,但可以获得读锁。
升级写锁(EnterWriteLock):当持有可升级的读锁的线程决定需要修改共享资源时,它可以调用 EnterWriteLock 方法来升级锁,而无需先释放读锁,这将阻塞其他所有尝试获取读锁或写锁的线程,直到写锁被释放。
public class Account
{private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();private int sharedData = 0;public void UpgradeableReadAndWriteData(int value){//进入升级读取模式rwLock.EnterUpgradeableReadLock();try{// 执行读操作 int currentData = sharedData;// 假设基于读取的数据,决定需要修改数据 if (currentData != value){// 升级到写锁,而不释放读锁 rwLock.EnterWriteLock();try{// 在写锁下,执行写操作 sharedData = value;Console.WriteLine($"{sharedData}写入,我的线程ID是{Thread.CurrentThread.ManagedThreadId}");}finally{Console.WriteLine($"退出写锁,我的线程ID是{Thread.CurrentThread.ManagedThreadId}");// 退出写锁,但保持读锁 rwLock.ExitWriteLock();}}}finally{Console.WriteLine($"退出升级读锁,我的线程ID是{Thread.CurrentThread.ManagedThreadId}");// 退出可升级的读锁 rwLock.ExitUpgradeableReadLock();}}}
4、Concurrent(并发集合)
BlockingCollection<T>
提供了一种线程安全的方式来在多个生产者线程和消费者线程之间共享数据。当集合为空时,尝试从中取数据的操作会被阻塞,直到有数据可用。同样地,当集合已满(如果设置了容量限制)时,尝试添加数据的操作也会被阻塞。
using System.Collections.Concurrent;BlockingCollection<int> collection = new BlockingCollection<int>();// 启动生产者任务
Task producerTask = Task.Run(() =>
{for (int i = 0; i < 10; i++){Console.WriteLine("生产者生产数据: " + i);collection.Add(i); // 将数据添加到集合中 Thread.Sleep(1000); // 模拟耗时操作 }// 通知消费者没有更多的数据将要添加 collection.CompleteAdding();
});// 启动消费者任务
Task consumerTask = Task.Run(() =>
{foreach (var item in collection.GetConsumingEnumerable()){Console.WriteLine("消费者消费数据: " + item);Thread.Sleep(500); // 模拟耗时操作 }
});// 等待生产者和消费者任务完成
Task.WaitAll(producerTask, consumerTask);
常用类:
ConcurrentBag<T>
这是一个无序的线程安全集合,允许线程安全地添加和移除元素。
ConcurrentDictionary<TKey, TValue>
这是一个线程安全的字典,支持线程安全地添加、移除和访问键值对。
ConcurrentQueue<T>
这是一个线程安全的先进先出(FIFO)集合,支持线程安全地入队和出队操作。
ConcurrentStack<T>
这是一个线程安全的后进先出(LIFO)集合,支持线程安全地推入和弹出操作。
Partitioner<TSource>
用于将数据划分为多个分区,以便并行处理。这通常与TPL(Task Parallel Library)一起使用,以便在多个线程或任务上并行处理数据。
OrderablePartitioner<TSource>
这是一个特殊的分区器,它保留了元素的顺序,允许在并行处理的同时保持元素的顺序。
三、异步流
允许你以异步的方式处理数据流,当你需要在不阻塞线程或其他重要线程的情况下处理大量数据时使用。关键字为IAsyncEnumerable<T>,它允许你以异步的方式枚举数据序列,而不需要一次性加载所有数据到内存中。
public class Account
{public async IAsyncEnumerable<int> GenerateAsyncStream(){for (int i = 0; i < 10; i++){await Task.Delay(1000);yield return i;yield return i + 1;}}
}
IAsyncEnumerable<int> asyncStream = new Account().GenerateAsyncStream();await foreach (int i in asyncStream)
{Console.WriteLine(i);
}
常见的并发编程方法还有异步编程和多线程编程等。
四、并发的注意
使用并发编程的时候应该避免以下及其其他问题的出现,通常并发编程的错误都是因为多个线程同时访问和修改共享资源,或者由于线程之间的同步和协调不当导致的。
1、竞态条件
竞态条件发生在两个或多个线程同时访问共享资源,并且它们的访问顺序会影响程序的结果,在计算共享数据时,由于多个线程计算顺序的不同,导致最终计算的结果也不同导致的。
2、死锁
当两个或多个线程相互等待对方释放资源时,导致所有线程都无法继续执行,这通常是因为线程间的锁顺序不一致导致的。
3、活锁
当线程们都在忙于响应其他线程的动作,但无法完成它们自己的任务时导致的。
4、饥饿
当其他线程一直占用资源而得不到释放时,某些线程长时间得不到执行的机会而导致的。
5、数据不一致
当多个线程没有正确同步对共享数据的访问时,可能会导致数据的不一致状态,这可能是因为一个线程正在读取数据,而另一个线程同时修改了这些数据。
相关文章:
并发编程实现
一、并行编程 1、Parallel 类 Parallel类是System.Threading.Tasks命名空间中的一个重要类,它提供数据并行和任务并行的高级抽象。 For和ForEach Parallel类下的For和ForEach对应着普通的循环和遍历(普通的for和foreach),但执行时会尝试在多个线程上…...
基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调)
基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调) 我的项目是基于EBAZ4205矿板的阈值可调的图像阈值二值化处理,可以通过按键调整二值化的阈值,key1为阈值加1,key4为阈值减1,key2为阈值加10,key5为阈值…...
人大金仓数据库报com.kingbase8.util.KSQLException: 致命错误: 用户 “SYSTEM“ Password 认证失败
com.kingbase8.util.KSQLException: 致命错误: 用户 “SYSTEM” Password 认证失败 解决办法: 问题在于用户权限只不足,相关配置文件在一般在 /data/sys hba.conf,修改IPV4 local connections选项中的改为trust。...
文件加密软件哪个好?文件加密软件排行榜前十名(好用软件推荐)
文件加密软件哪个好?这是许多个人和企业用户在面临数据保护需求时所关心的问题。随着数字化时代的推进,数据安全问题日益凸显,文件加密软件成为了保护数据安全的重要手段。本文将为您介绍当前市场上排名前十的文件加密软件,帮助您…...
Netty的第一个简单Demo实现
目录 说明需求ClientServer写法总结 实现运行 说明 Netty 的一个练习,使用 Netty 连通 服务端 和 客户端,进行基本的通信。 需求 Client 连接服务端成功后,打印连接成功给服务端发送消息HelloServer Server 客户端连接成功后࿰…...
K8S 哲学 - 服务发现 services
apiVersion: v1 kind: Service metadata:name: deploy-servicelabels:app: deploy-service spec: ports: - port: 80targetPort: 80name: deploy-service-podselector: app: deploy-podtype: NodePort service 的 endPoint (ep) 主机端口分配方式 两…...
Springboot工程创建
目录 一、步骤 二、遇到的问题及解决方案 一、步骤 打开idea,点击文件 ->新建 ->新模块 选择Spring Initializr,并设置相关信息。其中组为域名,如果没有公司,可以默认com.example。点击下一步 蓝色方框部分需要去掉,软件包…...
日本站群服务器的优点以及适合该服务器的业务类型?
日本站群服务器的优点以及适合该服务器的业务类型? 日本站群服务器是指位于日本地区的多个网站共享同一台服务器的架构。这种服务器架构有着诸多优点,使其成为许多企业和网站管理员的首选。以下是日本站群服务器的优点以及适合该服务器的业务类型的分析࿱…...
堆的应用2——TOPK问题
TOPK问题 TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。 比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。 情况1——数据量小 对于Top-K问题,能想到的最简单直接的方式就…...
leetcode-5. 最长回文子串
题目描述 给你一个字符串 s,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例 1: 输入:s "babad" 输出:"bab" 解释:"aba"…...
【Flask 系统教程 1】入门及配置
当你开始学习 Flask 时,了解如何进行基本的配置是非常重要的。Flask 是一个简单而灵活的 Python Web 框架,它允许你快速构建 Web 应用程序,并且易于学习。在这篇博客中,我将介绍如何从零开始进行 Flask 的基础配置,适合…...
石家庄河北银行的
有些时候河北石家庄这边的甲方客户人员就是太苛刻了,尤其是银行业 比如河北银行的信息部的卢斌,兰州人,这个人的人品极度恶劣,对乙方的外包人员特别苛刻,像个大爷一样。自己什么都不会,连sql 都不会写&…...
【CCNP ENCOR OCG】CHAPTER 2》Spanning Tree Protocol
目录 “Do I Know This Already?” Quiz Foundation Topics Spanning Tree Protocol Fundamentals 802.1D Port States Spanning Tree Path Cost Root Bridge Election Locating Root Ports Locating Blocked Designated Switch Ports Verification of VLANs on Trun…...
docker无法映射/挂载根目录
docker无法映射(挂载)根目录下的文件夹只能映射家目录 最近想要使用nas-tools做做刮削,电影存在一个机械磁盘里,机械磁盘被挂载到/data1下,发现一个很奇怪的问题,docker只能挂载成功home目录下的文件夹&am…...
C++中不要重新定义继承而来的non-virtual函数
在 C 中,重定义继承而来的 non-virtual(非虚)函数通常是不推荐的,原因如下: 隐藏父类的实现:如果在派生类中重定义了一个非虚函数,这将隐藏父类中具有相同名称和参数的函数。这意味着即使通过基…...
C++ 对象型参数和返回值
对象型参数和返回值 1.对象型类型作为函数的参数2.对象型参数作为函数的返回值 1.对象型类型作为函数的参数 使用对象类型作为函数的参数或者返回值,可能会产生一些不必要的中间对象 例子: // 使用对象类型作为函数的参数 void test1(Car car) {}完整代…...
LeetCode 字符串专题——KMP算法_28. 找出字符串中第一个匹配项的下标
字符串专题——KMP算法 KMP算法例题 KMP算法 待更新 例题 https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/ class Solution {vector<int> next;void getNext(string s){int j-1;next[0]-1;int lens.size();for(int i…...
上班不想用脑子写代码了怎么办?那就试试Baidu Comate啊宝贝
本文目录 前言1、视频编程实战1.1、熟悉代码库中的代码1.2、参考现有代码编写新代码 2、下载使用教程3、使用体验3.1、AutoWork 产品测评3.2、解决有关ajax请求后重定向问题3.3、询问编程相关知识3.3.1、cookie和session的区别与联系3.3.2、数据库中主键外键的相关知识 4、问题…...
【管理咨询宝藏94】某国际咨询公司供应链财务数字化转型方案
本报告首发于公号“管理咨询宝藏”,如需阅读完整版报告内容,请查阅公号“管理咨询宝藏”。 【管理咨询宝藏94】某国际咨询公司供应链&财务数字化转型方案 【格式】PDF版本 【关键词】国际咨询公司、制造型企业转型、数字化转型 【核心观点】 - 172…...
C++_使用邻接表(链表-指针)实现有向图[完整示例及解释]
这个程序是一个图的实现,使用邻接表来表示图的结构: 1. 结构定义部分: - AdjListNode 结构定义了邻接表中的节点,每个节点包含一个名称和一个指向下一个邻接节点的指针。 - Node 结构定义了图中的节点,每个节点…...
Gitlab自动化测试的配置
1. 代码分支命名规范检测 Setting → Repository → Push rules → Branch name,添加分支命名规范对应的正则表达式。如: ^(Release|Tag|Develop|Feature)_._.|Main$ 表示分支名只能以以下关键字之一开头:Release、Tag、Develop和Feature。 …...
Qwen-Audio:推动通用音频理解的统一大规模音频-语言模型(开源)
随着人工智能技术的不断进步,音频语言模型(Audio-Language Models)在人机交互领域变得越来越重要。然而,由于缺乏能够处理多样化音频类型和任务的预训练模型,该领域的进展受到了限制。为了克服这一挑战,研究…...
杭州破冰之举:全面取消住房限购,激发市场新活力
在房地产市场调控的浪潮中,杭州再次走在了前列,于2024年3月14日宣布全面取消二手房限购政策,此举在行业内引发了广泛关注。作为中国经济活力较强的二线城市之一,杭州的这一决策不仅体现了地方政府在房地产市场调控上的灵活应变,也释放出对市场流动性和经济发展的积极信号。…...
ICode国际青少年编程竞赛- Python-1级训练场-变量练习
ICode国际青少年编程竞赛- Python-1级训练场-变量练习 1、 a 8 for i in range(8):Dev.step(a)Dev.turnRight()a - 12、 a 3 for i in range(4):Dev.step(a)Dev.turnRight()a a 1 Dev.step(5)3、 a 4 for i in range(4):Dev.step(2)Dev.step(-5)Dev.step(3)Spaceship.…...
学习STM32第二十天
低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz,当板载8MHz晶振时,系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN,在文件stm32f4xx.h中可修…...
智能BI(后端)-- 系统异步化
文章目录 系统问题分析什么是异步化?业务流程分析标准异步化的业务流程系统业务流程 线程池为什么需要线程池?线程池两种实现方式线程池的参数线程池的开发 项目异步化改造 系统问题分析 问题场景:调用的服务能力有限,或者接口的…...
AI绘画Stable Diffusion 插件篇:智能标签提示词插件sd-danbooru-tags-upsampler
大家好,我是向阳。 关于智能标签提示词插件,在很早之前就介绍过很多款了,今天再给大家介绍一款智能标签提示词插件sd-danbooru-tags-upsampler。该智能提示词插件是今年2月23号才发布的第一版V0.1.0,算是比较新的智能提示词插件。…...
Android OpenMAX(六)OMXStore
在前面两节的学习中我们知道了OMX Core是用来管理(查询/创建/销毁)Android平台上的硬件编解码组件的。这一节我们再向上一层,Android平台除了提供有硬件编解码组件支持,还内置了一些软件编解码组件,为了统一管理所有(软/硬)编解码组件,Android在OMX Core之上又抽象了一…...
Ubuntu下halcon软件的下载安装
由于工作需求,点云配准需要使用halcon进行实现,并且将该功能放入QT界面中 1.下载halcon 进入halcon官网进行下载 官网链接:https://www.mvtec.com/products/halcon/ 注意:要注册登陆之后才能进行下载 接着点击Downloads->H…...
『ZJUBCA Collaboration』WTF Academy 赞助支持
非常荣幸宣布,浙江大学区块链协会收到WTF Academy的赞助与支持,未来将共同开展更多深度合作。 WTF Academy是开发者的Web3开源大学,旨在通过开源教育让100,000名开发者进入到Web3。截止目前,WTF开源教程在GitHub收获超15,000 ⭐&a…...
建设标准 免费下载网站/灰色词优化培训
在 2003 系统 IIS6 下,经常出现 w3wp.exe 的内存占用不能及时释放和 CPU 占用居高不下的问题,从而导致服务器响应速度很慢。怎样才能找出是哪一个站点出问题呢? 首先给每个站点都建一个应用程序池,这样便于找出问题出在哪一个站点…...
邯郸网站制作外包/百度关键词价格查询软件
题目: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例: 输入:“23” 输出:[“ad”, “ae”, “af”, “bd”, “…...
沛县可以做网站的单位/电脑培训班零基础网课
1.TortoiseHg 设置语言成中文 其实设置语言的方法在文档里有详细说明:如果你安装后还是英文,想要切换语言的话,只需要设置环境变量,增加一个 LANGUAGE,设置为zh_CN 就可以了 哪里设置环境变量?系统属性&…...
网站开发技术试验总结/网络营销策划师
Tornado是什么?Tornado是一个用Python编写的异步HTTP服务器,同时也是一个web开发框架。Tornado 优秀的大并发处理能力得益于它的 web server 从底层开始就自己实现了一整套基于 epoll 的单线程异步架构。同步、异步编程差异对于同步阻塞型Web服务器&…...
js模版网站/重庆今天刚刚发生的重大新闻
🍯前端~CSS 简介:为页面中的元素添加样式 目录 1、基础选择器 2、组合选择器 3、属性选择器 4、伪类选择器 5、背景样式(各种样式) 使用方式:》》》 行内样式:样式定义在行内部标签上内部样式:css样式定…...
wordpress免费商城主题/潍坊自动seo
ASP.NET 支持两组性能计数器:系统和应用程序。前者在 ASP.NET 性能计数器对象中的 PerfMon 中公开;后者在 ASP.NET Applications 性能对象中公开。ASP.NET 性能对象中的 State Server Sessions 计数器(仅适用于在其中运行状态服务器的服务器计…...