.net core 多线程下使用 Random 会出现的bug

先看原文:

Working with System.Random and threads safely in .NET Core and .NET Framework

https://andrewlock.net/building-a-thread-safe-random-implementation-for-dotnet-framework/

我的结论:

.net 6 之前,如果习惯构建了一个静态的 Random 对象,然后业务代码里直接使用 random.Next() 方法,多线程竞争下,会有一定概率返回0。

.net 6 时,修正了这个默认创建时的多线程存在的bug。但又没完全解决。如果这个公共的 Random 方法初始化的适合使用了自定义随机种子,则还是会存在多线程竞争下出现返回0情况。

原文提供了在 .net 6 之前版本的一些解决办法,我的建议是使用 random.Next(1, 10000) 这样的方法生成随机数。

原文测试用代码片段[改]:


using System;
using System.Linq;
using System.Threading.Tasks; public class Program { public static void Main() {
// This isn't safe, don't do it
Random rng = new Random(); // create a shared Random instance
Parallel.For(0, 10, x => // run in parallel
{
var numbers = new int[10_000];
for (int i = 0; i < numbers.Length; ++i)
{
numbers[i] = rng.Next(); // Fetch 10,000 random numbers, to trigger the thread-safety issues
} var numZeros = numbers.Count(x => x == 0); // how many issues were there?
var avg = numbers.Average();
Console.WriteLine($"Received {numZeros} zeroes avg:{avg} {numbers[0]}");
});
}
}

当然好奇的脚步不止于此,为什么文章说的,大部分人习惯直接调用 .Next() 方法,而不是 .Next(min,max) 这样的方法呢?

我姑且认为是性能问题,于是增加了一个性能测试代码片段,用于生成 (1,100)区间内的随机数:

    public class RandomT
{
System.Random random1 = new System.Random(1);
System.Random random2 = new System.Random(1); System.Random random11 = new System.Random();
System.Random random22 = new System.Random(); [Benchmark]
public int RandomSeedByRange() => random1.Next(1, 100); [Benchmark]
public int RandomSeedByMod() => random2.Next() % 100 + 1; [Benchmark]
public int RandomDefaultByRange() => random11.Next(1, 100); [Benchmark]
public int RandomDefaultByMod() => random22.Next() % 100 + 1;
}

BenchmarkDotNet=v0.13.2, OS=ubuntu 20.04
Intel Xeon Gold 6133 CPU 2.50GHz, 1 CPU, 2 logical and 2 physical cores
.NET SDK=6.0.200
[Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT AVX2
DefaultJob : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT AVX2
Method Mean Error StdDev
RandomSeedByRange 15.096 ns 0.1449 ns 0.1210 ns
RandomSeedByMod 14.759 ns 0.1298 ns 0.1014 ns
RandomDefaultByRange 9.310 ns 0.0702 ns 0.0548 ns
RandomDefaultByMod 4.925 ns 0.1387 ns 0.2393 ns

性能果然是直接使用 .Next() 最优。两者差距有一倍。

但是,指定随机种子后,两者就没有差距了,这就有点让人想不通了。

.net core 多线程下使用 Random 会出现bug的更多相关文章

  1. 一个实现单线程/多线程下代码调用链中传递数据的处理类: CallContext(LogicalSetData,LogicalGetData),含.net core的实现

    详情请参考原文:一个实现单线程/多线程下代码调用链中传递数据的处理类: CallContext

  2. Vector 是线程安全的,是不是在多线程下操作Vector就可以不用加Synchronized

    如标题一样,如果之前让我回答,我会说,是的,在多线程的环境下操作Vector,不需要加Synchronized. 但是我今天无意间看到一篇文章,我才发现我之前的想法是错误的,这篇文章的地址: http ...

  3. Java进阶专题(十五) 从电商系统角度研究多线程(下)

    前言 ​ 本章节继上章节继续梳理:线程相关的基础理论和工具.多线程程序下的性能调优和电商场景下多线程的使用. 多线程J·U·C ThreadLocal 概念 ​ ThreadLocal类并不是用来解决 ...

  4. 多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用

    本篇文章主要介绍下多线程下NSOperation.NSBlockOperation.NSInvocationOperation.NSOperationQueue的使用,列举几个简单的例子. 默认情况下 ...

  5. python 类变量 在多线程下的共享与释放问题

    最近被多线程给坑了下,没意识到类变量在多线程下是共享的,还有一个就是没意识到 内存释放问题,导致越累越大 1.python 类变量 在多线程情况 下的 是共享的 2.python 类变量 在多线程情况 ...

  6. Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask

    CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就是CyclicBarrier.CyclicBarrier从字面理解是指循环屏障,它可以协同多个线程,让多个线程在这个屏障前等待,直到 ...

  7. Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger

    前言 在多线程环境下,JDK给开发者提供了许多的组件供用户使用(主要在java.util.concurrent下),使得用户不需要再去关心在具体场景下要如何写出同时兼顾线程安全性与高效率的代码.之前讲 ...

  8. 多线程下C#如何保证线程安全?

    多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...

  9. 多线程下HashMap的死循环问题

    多线程下[HashMap]的问题: 1.多线程put操作后,get操作导致死循环.2.多线程put非NULL元素后,get操作得到NULL值.3.多线程put操作,导致元素丢失. 本次主要关注[Has ...

  10. ASP.NET多线程下使用HttpContext.Current为null解决方案 2015-01-22 15:23 349人阅读 评论(0) 收藏

    问题一:多线程下获取文件绝对路径 当我们使用HttpContext.Current.Server.MapPath(strPath)获取绝对路径时HttpContext.Current为null,解决办 ...

随机推荐

  1. yapi 个人空间 这个分组的问题

    总结:yapi个人空间分组的问题,我暂时不用理睬 他自己自由,但是 不允许他 创建非个人空间的分组.这点留意 避免不统一.所有的分组都必须我自己来创建,不允许他们私自创建.

  2. HBase-Hbase启动异常java.lang.IllegalArgumentException: object is not an instance of declaring class

    1.问题描述 HBase启动时异常如下: java.lang.IllegalArgumentException: object is not an instance of declaring clas ...

  3. 多层PCB线路板制作流程

    PCB制作第一步是整理并检查pcb多层线路板布局(Layout).电路板制作工厂收到PCB设计公司的CAD文件,由于每个CAD软件都有自己独特的文件格式,所以深圳PCB板厂会转化为一个统一的格式Ger ...

  4. 【分布式】load balance 03-一致性哈希算法 java 实现

    负载均衡系列专题 01-负载均衡基础知识 02-一致性 hash 原理 03-一致性哈希算法 java 实现 04-负载均衡算法 java 实现 本节我们来看一下如何实现一个一致性 hash 框架. ...

  5. 解决邮件客户端QQ Mail及Thunderbird无法登入Outlook的问题

    最近无论是安卓手机的邮件客户端, 或者是 Ubuntu 下的 Thunderbird 都无法登入 Outlook 账号, 原因是需要开启双因素验证. 这个在 Outlook 界面上是不能直接设置的, ...

  6. 51单片机(STC89C52)在Ubuntu下的开发

    简介 都是8051衍生的8位单片机, STC单片机有89/90/10/11/12/15这几个大系列, 每个系列的特点如下 89系列是传统的8051单片机, 烧录方法有区别, 但是功能上可以和AT89系 ...

  7. 【OpenGL ES】透视变换原理

    1 前言 ​ MVP矩阵变换 中主要介绍了模型变换(平移.旋转.对称.缩放)和观测变换基本原理,本文将介绍透视变换的基本原理. ​ 如下图,近平面和远平面间棱台称为视锥体,表示可见区域范围,视锥体以外 ...

  8. 手动实现apply、call、bind

    手动实现apply.call.bind 每个Function对象都存在apply().call().bind()方法,其作用都是可以在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函 ...

  9. 使用xampp安装部署mantis

    快速教程请参考: 点击打开链接   http://download.csdn.net/detail/indexman/6830003 --------------------------- Dylan ...

  10. pigz命令

    多线程的解压缩文件 语法格式:pigz 参数 文件名 常用参数 -- 显示压缩后的内容 -p 设置线程数 -b 设置文件数据块大小 -q 静默执行模式 -d 将压缩文件恢复为原始文件 -r 递归处理所 ...