在C#中轻松生成线程安全的随机值——与Tim Corey深入探索
生成随机数是每个开发者都会遇到的任务之一。 虽然创建一个简单的随机值似乎很简单,但在C#中确保线程安全,特别是在多线程环境中,可能很棘手。 在他的视频"Easy Thread-Safe Random Values in C#"中,Tim Corey探讨了C#中随机数的工作原理、旧方法的陷阱以及在处理多个线程时如何实现线程安全。
在本文中,我们将按照Tim的解释,为线程安全的随机数生成、最佳实践和相关同步技术提供详细说明。
Introduction to Random Values and Thread Safety in C
Tim一开始指出在C#中生成随机值通常很简单。 然而,有不同的方法来实现,选择取决于您的代码是将在单个线程还是多个线程中并发运行。 Tim强调此视频设计为开发人员的快速实用指南,提供简单示例和线程安全的深刻见解。
他在一个控制台应用程序中使用Visual Studio 2026预览版和.NET 10示例,但向观众保证相同的代码在Visual Studio 2022和.NET 9中也适用。对于那些想跟随的人,Tim在说明中提供了源代码。
Traditional Random Number Generation in C
Tim首先展示了使用Random类生成随机数的经典方法。 他创建了两个实例,RNG1和RNG2,并演示如何使用Next()生成随机整数。
Random rng1 = new();
Random rng2 = new();
for(int i = 0; i < 10; i++)
{
int output1 = rng1.Next(1, 101);
int output2 = rng2.Next(1, 101);
Console.WriteLine($"Random 1: {output1}, Random 2: {output2}");
}Tim解释说,运行这段代码为每个实例产生不同的数字,但这段代码不是线程安全的。 在多线程环境中,如果两个线程访问同一个Random实例,可能会获得意外的值或重复,因为Random对象的内部状态可能同时被访问。
他指出,一种确保线程安全的方法是为每个线程使用一个Random实例。 对于工作线程、异步方法或可能并发运行代码的任何情况,这一点很重要。 在没有适当同步的情况下在多个线程间共享相同的实例可能导致竞争条件、错误的值,甚至若管理不当会引起死锁。
使用种子获得可预测的随机数
Tim接着演示了使用种子。 种子是决定生成数序列的起始值。 例如,使用25作为RNG1和RNG2的种子:
Random rng1 = new(25);
Random rng2 = new(25);这两个实例产生相同的数字序列。 Tim强调这是一种功能,而不是一个错误,对于需要可重复性的场景很有用。 这可以帮助进行单元测试或调试多线程程序,当您需要在两个或多个线程中重现一个随机值序列时。
使用Random.Shared提供线程安全的随机数
Tim介绍了Random.Shared,一种现代、线程安全的生成随机数的方法。 与手动创建实例不同,Random.Shared是一个静态、共享资源,能自动处理并发访问:
int output1 = Random.Shared.Next();
int output2 = Random.Shared.Next();通过这种方法,您无需担心锁、静态构造函数或共享资源。 .NET内置的线程安全集合和Random.Shared实例使得并发使用多个线程是安全的。
Random.Shared的优点
Tim解释了此方法的几个好处:
无需实例化:您不需要为每个线程单独实例。
默认线程安全:可以在并行任务或工作线程中安全使用。
- 简单的API:支持整数、小数,甚至数组洗牌。
他确实指出了一个限制:您不能设置一个种子,意味着序列不可预测。 在需要在多次运行中相同顺序的场景中,您仍应使用带有种子的单独实例。
确保复杂代码中的线程安全
虽然Random.Shared在内部处理线程安全,Tim的例子让我们可以讨论C#中一般的线程安全技术。 在更复杂的代码或多线程环境中,您通常需要正确同步以避免竞争条件并确保数据完整性。 一些常用技术包括:
锁语句:防止多个线程同时访问临界区。
静态成员和静态构造函数:可以用来安全初始化共享资源。
线程安全集合:如ConcurrentQueue、ConcurrentStack和ConcurrentDictionary,可以安全地进行并发访问。
- 互斥(Mutex/Monitor):确保一次只有一个线程可以执行一段代码。
Tim解释说,对于大多数随机数的情况,Random.Shared消除了这些技术的必要,但在具有共享资源的多线程应用程序中,这些方法是必需的,以避免死锁和意外值。
来自Tim Corey的实用指南
Tim为在多线程应用中安全使用随机数提供了明确指导:
使用Random.Shared以简化:当您只需要一个随机值并且性能很重要时,这是理想的选择。
使用种子实例以实现可重复性:在跟踪相同数据或在多线程环境中调试时是必要的。
在密码学中避免使用Random:为确保安全,请使用加密库。
- 了解线程安全的基础:知道什么时候您的代码被多个线程访问,并仅在必要时实现同步。
他向开发者保证,Random.Shared在每毫秒进行几百万次调用时仍然有效,并且能高效地处理并发访问。
Conclusion: Safe and Simple Random Numbers in C
Tim Corey的视频演示了在C#中生成线程安全的随机数比许多开发者预想的要简单。通过使用Random.Shared,您可以避免许多与多线程环境相关的陷阱。 在需要可预测序列的情况下,使用带种子的单独实例提供了一种可靠的方法。
了解线程安全、关键部分和同步技术确保您的代码在多线程应用中保持正确并具有良好的性能。 遵循Tim的指导,开发者可以自信地编写对工作线程、异步方法和并行任务线程安全的代码,而无需担心竞争条件、死锁或意外值。

