leo*_*loy 6 .net c# random concurrency
我用Paint.Net插件调试了一些问题,当有几个线程从单个实例调用一个方法时,我偶然发现了Random类的一些问题.
出于一些奇怪的原因,似乎如果我不阻止并发访问,通过同步被调用的方法,我的Random实例开始表现......随机(但在不好的意义上).
在下面的示例中,我创建了几百个线程,它们可以重新调用一个Random对象.当我运行它时,我有时(不总是,但几乎)得到明显错误的结果.如果我取消注释Synchronized方法注释,问题永远不会发生.
using System;
using System.Threading;
using System.Runtime.CompilerServices;
namespace testRandom {
class RandTest {
static int NTIMES = 300;
private long ac=0;
public void run() { // ask for random number 'ntimes' and accumulate
for(int i=0;i<NTIMES;i++) {
ac+=Program.getRandInt();
System.Threading.Thread.Sleep(2);
}
}
public double getAv() {
return ac/(double)NTIMES; // average
}
}
class Program
{
static Random random = new Random();
static int MAXVAL = 256;
static int NTREADS = 200;
//[MethodImpl(MethodImplOptions.Synchronized)]
public static int getRandInt() {
return random.Next(MAXVAL+1); // returns a value between 0 and MAXVAL (inclusive)
}
public static void Main(string[] args) {
RandTest[] tests = new RandTest[NTREADS];
Thread[] threads = new Thread[NTREADS];
for(int i=0;i<NTREADS;i++) {
tests[i]= new RandTest();
threads[i] = new Thread(new ThreadStart(tests[i].run));
}
for(int i=0;i<NTREADS;i++) threads[i].Start();
threads[0].Join();
bool alive=true;
while(alive) { // make sure threads are finished
alive = false;
for(int i=0;i<NTREADS;i++) { if(threads[i].IsAlive) alive=true; }
}
double av=0;
for(int i=0;i<NTREADS;i++) av += tests[i].getAv();
av /= NTREADS;
Console.WriteLine("Average:{0, 6:f2} Expected:{1, 6:f2}",av,MAXVAL/2.0);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出示例(具有上述值):
Average: 78.98 Expected:128.00
Press any key to continue . . .
Run Code Online (Sandbox Code Playgroud)
这是一个已知的问题吗?从没有同步的多个线程调用Random对象是不正确的?
更新:根据答案,文档声明随机方法不是线程安全的 - mea culpa,我应该已经读过.也许我之前已经阅读过但不认为它如此重要 - 人们可以(懒散地)认为,在两个线程同时进入同一方法的极少数情况下,可能发生的最坏情况是那些调用得到错误的结果 - 不是一个巨大的交易,如果我们没有太在意随机数质量......但问题是真正灾难性的,因为对象是不一致的状态,并从它返回返回不停零-作为注意到这里.
Jon*_*eet 17
出于一些奇怪的原因
这不是很奇怪的- Random被证明并非是线程安全的.
这是一种痛苦,但这就是生活.有关更多信息,请参阅我在Random上的文章,以及有关如何为每个线程创建实例的建议,以防止在多个线程中使用相同的种子启动.
本Random类不是线程安全的.
来自文档:
Any instance members are not guaranteed to be thread safe
Run Code Online (Sandbox Code Playgroud)
尝试实现该ThreadStatic属性,而不是同步哪个将导致所有线程阻塞.
| 归档时间: |
|
| 查看次数: |
1049 次 |
| 最近记录: |