.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. 单片机 IAP 功能基础开发篇之APP升级(二)

    1.前言 上一篇单片机 IAP 功能基础开发篇之APP升级(一)讲到了单片机 IAP 功能给 APP 程序升级的设计思路,这篇介绍的是具体实现方式. 下一篇单片机 IAP 功能基础开发篇之APP升级( ...

  2. Exadata刷机快速参考

    本文以Exadata X8 HC 1/4 rack为例,介绍整个Exadata刷机的步骤. 我理解刷机最关键的就两大步骤:第一步是所有机器刷OS,第二步是使用OEDA一键刷机.至于其它所有工作都是在为 ...

  3. BoolToStr、TBooleanHelper、Boolean 转 字符串

    方法1:直接使用 BoolToStr procedure TForm3.btn1Click(Sender: TObject); var a, b: Boolean; begin a := True; ...

  4. Hive-分区取TOP N问题

    问题背景 设想你对用户在不同品类上的行为打分聚合后得到这样一个表 user_cate_score uid cate score 1 1 0.3 2 2 0.5 8 3 0.9 现在,你想将每个品类的T ...

  5. 树莓派安装freeswitch

    树莓派版本: Raspberry Pi 4B 操作系统 : Ubuntu Server 20.04_x64 freeswitch版本 : 1.10.3 1.下载freeswitch源代码 wget h ...

  6. CF1826D Running Miles

    题目链接 题解 知识点:贪心,前缀和,枚举. 首先考虑一个贪心结论,选择区间端点一定是两个最大值,因此 \(i_1 = l,i_3 = r\) . 考虑变形式子 \((b_l + l) + b_{i_ ...

  7. SpringCloud Ribbon负载均衡服务调用实战

    介绍 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具. 主要功能是提供客户端的软件负载均衡算法和服务调用.Ribbon客户端组件提供一系列完善 ...

  8. virtualapp启动流程源码分析

    virtualapp启动流程分析 1. 首先是启动本身,执行Vpp 的attachBaseContext @Override protected void attachBaseContext(Cont ...

  9. 文件的拓展及文件函数,定义函数及函数参数---day09

    1.文件的拓展模式 utf-8 编码格式下,默认一个中文三个字节,一个英文或符号占用一个字节 read() 功能:读取字符的个数(里面的参数代表字符个数) seek() 功能:调整指针的位置(里面的参 ...

  10. 类型判断,代码块,流程控制及循环---day05

    1.类型判断isinstance 用来做判断类型 语法: 用法一: isinstance(要判断的值,要判断的类型) 返回的是真或者假 用法二: isinstance(要判断的值,(可能的类型))如果 ...