看Elsa-core源代码中看到的,Elsa-core中所有保存数据的方法似乎使用同一个Save方法。如下图:

那么为什么要使用这玩意,我还是头一次见这玩意????

好吧,我承认我自己菜。我自个儿也该保持谦虚态度学习学习了。

先看下这个SemaphoreSlim类的描述

(我买的正版Resharp 2022)反编译代码如上图。

翻译过来就是 “限制当前访问资源或池中资源的线程数”,真的是这样的吗? 试一试...

我的代码仓库  https://github.com/qiqiqiyaya/Learning-Case/tree/main/SemaphoreSlim ,测试例子。

例一

在B乎中看到一篇文章 ,链接地址  https://zhuanlan.zhihu.com/p/158777952

我copy他的例子测试了下,如下图:

// 现在有10个人要过桥
// 但是一座桥上只能承受5个人,再多桥就会塌
static void SemaphoreTest()
{
var semaphore = new SemaphoreSlim(5);
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(100); // 排队上桥
var index = i; // 定义index 避免出现闭包的问题
Task.Run(() =>
{
semaphore.Wait();
try
{
Console.WriteLine($"第{index}个人正在过桥。");
Thread.Sleep(5000); // 模拟过桥需要花费的时间
}
finally
{
Console.WriteLine($"第{index}个人已经过桥。");
semaphore.Release();
}
});
}
}

运行结果,与B乎上作者的结果一样。

这里有个问题,该作者使用Task.Run 然后在其中添加了 Thread.Sleep(5000); ,这会阻塞当前的线程,导致执行 Task 任务的“任务调度器”开启了 10个线程。

关于什么是 Task ,理解 Task ,请阅读大佬的文章,非常Nice链接 https://www.cnblogs.com/artech/p/task_scheduling.html

列二,如果在异步Async/Await中是什么情况呢?

static void SemaphoreTest1()
{
var semaphore = new SemaphoreSlim(5);
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(100); // 排队上桥
var index = i; // 定义index 避免出现闭包的问题
Task.Run(async () =>
{
Console.WriteLine($"第{index}个人已抵达桥边上。线程Id " + Thread.CurrentThread.ManagedThreadId);
semaphore.Wait();
try
{
Console.WriteLine($"第{index}个人正在过桥。线程Id " + Thread.CurrentThread.ManagedThreadId);
//Thread.Sleep(5000); // 模拟过桥需要花费的时间
await Task.Delay(5000);
}
finally
{
Console.WriteLine($"第{index}个人已经过桥。线程Id " + Thread.CurrentThread.ManagedThreadId);
semaphore.Release();
}
});
}
}

将 Thread.Sleep(5000); 换成了 await Task.Delay(5000); 使用 async/await 。结果如下:

从结果上看,例如:第1个人 线程Id 3 上桥,在执行 await Task.Delay(5000); (模拟过桥需要花费的时间)后,线程Id变成了 12 。这是执行 Task 的任务调度器(Task默认调度器是线程池)作用的效果。这不是本次随笔的重点。

再次强调关于理解Task,请参考 https://www.cnblogs.com/artech/p/task_scheduling.html 。

再次强调Task与线程Thread是两个东西,Task可以理解为一个任务,那么这个任务由Thread去执行,至于由哪一个Thread 去执行,这就由 “任务调度器” 去决定了。

从结果上看,执行了五个Task之后,就阻止后续Task再往下执行代码了。

列二中使用了 semaphore.Wait(); 同步阻塞 , 导致后续Task中使用一个之前空闲的Id为3的线程 (Id为3的线程执行到 await Task.Delay(5000) 后阻塞了,该线程被调度器拿去执行新的Task任务),并创建了另外4个新的执行Task的线程。

结论:

1.SemaphoreSlim会限制访问资源的线程数

2.在异步async/await情况下,SemaphoreSlim会限制正在执行访问资源的Task的数量

例三

static void SemaphoreTest2()
{
var semaphore = new SemaphoreSlim(5);
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(100); // 排队上桥
var index = i; // 定义index 避免出现闭包的问题
Task.Run(async () =>
{
Console.WriteLine($"第{index}个人已抵达桥边上。线程Id " + Thread.CurrentThread.ManagedThreadId);
await semaphore.WaitAsync();
try
{
Console.WriteLine($"第{index}个人正在过桥。线程Id " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(5000);// 模拟过桥需要花费的时间
}
finally
{
Console.WriteLine($"第{index}个人已经过桥。线程Id " + Thread.CurrentThread.ManagedThreadId);
semaphore.Release();
}
});
}
}

执行结果

例三中我使用了 await semaphore.WaitAsync(); ,也就是说不存在同步阻塞代码了,全部都是异步。

异步下遇到await,执行等待,那么当前执行这个Task的线程可能会被“任务调度器拿去执行别的Task”

结论:

1.在异步async/await情况下,SemaphoreSlim会限制正在执行访问资源的Task的数量,  与例二第二个结论一致。

异步下的Lock锁

鉴于SemaphoreSlim的特殊性,可以使用其通过程序角度来实现“”(叫乐观锁、还是悲观锁???,我去,两者好像都不是

乐观锁与悲观锁定义如下图

如下图代码:

重点代码  SemaphoreSlim _semaphore = new(1) 

如果真要说明,我觉得是最多像 悲观锁 ,但又不全是。这里的SemaphoreSlim只是说同一时刻只准一个线程或正在执行的Task做保存操作,那么如果是分布式程序呢,另一个程序此时也执行保存操作?

我觉得其真实原因是:使用SemaphoreSlim可以实现异步下的 Lock 锁。

.Net SemaphoreSlim的更多相关文章

  1. 【C#】【Thread】Semaphore/SemaphoreSlim信号量

    System.Threading.Semaphore 类表示一个命名(系统范围)信号量或本地信号量. 它是一个对 Win32 信号量对象的精简包装. Win32 信号量是计数信号量,可用于控制对资源池 ...

  2. C#并行编程 (Barrier,CountdownEvent,ManualResetEventSlim,SemaphoreSlim,SpinLock,SpinWait )

    背景 有时候必须访问变量.实例.方法.属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行. 当任务和线程要 ...

  3. 第十三节:实际开发中使用最多的监视锁Monitor、lock语法糖的扩展、混合锁的使用(ManualResetEvent、SemaphoreSlim、ReaderWriterLockSlim)

    一. 监视锁(Monitor和lock) 1. Monitor类,限定线程个数的一把锁,两个核心方法: Enter:锁住某个资源. Exit:退出某一个资源. 测试案例:开启5个线程同时对一个变量进行 ...

  4. C# SemaphoreSlim 实现

    当多个任务或线程并行运行时,难以避免的对某些有限的资源进行并发的访问.可以考虑使用信号量来进行这方面的控制(System.Threading.Semaphore)是表示一个Windows内核的信号量对 ...

  5. 《C#多线程编程实战》2.4 SemaphoreSlim

    这个简单多了. 理解也是很好理解. 比上一个mutex好理解多了. 这个SemaphoreSlim是干什么呢? 就是限制线程的来访问. 好比说一次只有两个,一次只有三个  这样的线程来访问资源. 有点 ...

  6. Semaphore and SemaphoreSlim

    https://msdn.microsoft.com/en-us/library/z6zx288a(v=vs.110).aspx The System.Threading.Semaphore clas ...

  7. SemaphoreSlim

    https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx Represents a ...

  8. 一次 .NET Core 中玩锁的经历:ManualResetEventSlim, Semaphore 与 SemaphoreSlim

    最近同事对  .net core memcached 缓存客户端 EnyimMemcachedCore 进行了高并发下的压力测试,发现在 linux 上高并发下使用 async 异步方法读取缓存数据会 ...

  9. Mutex vs Semaphore vs Monitor vs SemaphoreSlim

    C#开发者(面试者)都会遇到Mutex,Semaphore,Monitor,SemaphoreSlim这四个与锁相关的C#类型,本文期望以最简洁明了的方式阐述四种对象的区别. 线程安全 教条式理解 如 ...

  10. SemaphoreSlim 实现

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/dz45693/article/deta ...

随机推荐

  1. 【JDBC】学习路径7-转账-commit事务操作

    现在我们要做一个转账系统. 第一章:创建一张新的表格(用户银行账户表格) 在之前的JDBC_01数据库中新增一个表格,名字为:Account   其中,有id.银行卡号.银行密码.账户余额. 创建表格 ...

  2. Linux软件包常见的几种下载、安装方法

    在线源下载和安装 如果服务器是处于在线状态,在使用默认下载源是外国的情况下,安装更新软件包往往会比较痛苦的存在,下载了许久来一个超时就gg了.国内有许多镜像源,完美的解决了这个问题. 对于rpm系列的 ...

  3. ZooKeeper 组件安装配置

    ZooKeeper 组件安装配置 下载和安装 ZooKeeper ZooKeeper最新的版本可以通过官网 http://hadoop.apache.org/zookeeper/ 来获取,安装 Zoo ...

  4. Kingbase V8R6集群安装部署案例---脚本在线一键缩容

    ​ 案例说明: KingbaseES V8R6支持图形化方式在线缩容,但是在一些生产环境,在服务器不支持图形化界面的情况下 ,只能通过脚本命令行的方式执行集群的部署或在线缩容. Tips: Kingb ...

  5. 跨语言调用C#代码的新方式-DllExport

    简介 上一篇文章使用C#编写一个.NET分析器文章发布以后,很多小伙伴都对最新的NativeAOT函数导出比较感兴趣,今天故写一篇短文来介绍一下如何使用它. 在以前,如果有其他语言需要调用C#编写的库 ...

  6. 《Java基础——break与continue用法详解》

    Java基础--break与continue用法详解       1. break语句: 规则: 1. 仅用于循环语句和switch语句当中,用于跳出循环. 2. 当只有一层循环时,则直接跳出循环,不 ...

  7. 7、System类

    System类 常见方法 exit 退出当前程序 System.out.println("ok1"); //1. exit(0) 表示程序退出 //2. 0 表示一个状态,正常的状 ...

  8. windows下 Rust 环境配置

    搭建 Visual Studio Code 开发环境 首先,需要安装最新版的 Rust 编译工具和 Visual Studio Code. Rust 编译工具:https://www.rust-lan ...

  9. 采用docker方式安装ElastAlert,图形化配置告警规则----具体内容有删改,仅供查看

    1.创建几个文件夹保存ElastAlert相关配置信息,用来挂载到容器中使用 2.编写核心配置,创建 ${ELASTALERT}/config/config.yaml用来存储核心配置: 3.Elast ...

  10. frpc穿透报错 日志显示 http: proxy error: no such domain 解决办法

    问题出在客户端的设置上,比如你的frps服务器IP为114.114.114.114,设置的vhost_http_port端口为 8080,在客户端设置的是域名fk.abc.com 指向frps所在服务 ...