gpt4 book ai didi

c# - 在 C# 中,使用 for 循环迭代数组是线程安全操作吗?使用 foreach 循环迭代 IEnumerable 怎么样?

转载 作者:行者123 更新时间:2023-12-02 06:52:27 25 4
gpt4 key购买 nike

根据我的理解,给定一个 C# 数组,从多个线程并发迭代数组的行为线程安全操作。

通过迭代数组我的意思是通过普通的旧for读取数组内的所有位置。循环。每个线程只是读取数组内内存位置的内容,没有人写入任何内容,因此所有线程都以一致的方式读取相同的内容。

这是一段执行我上面编写的代码:

public class UselessService 
{
private static readonly string[] Names = new [] { "bob", "alice" };

public List<int> DoSomethingUseless()
{
var temp = new List<int>();

for (int i = 0; i < Names.Length; i++)
{
temp.Add(Names[i].Length * 2);
}

return temp;
}
}

所以,我的理解是方法DoSomethingUseless 线程安全并且无需替换 string[]具有线程安全类型(例如 ImmutableArray<string>)。

我说得对吗?

现在假设我们有一个 IEnumerable<T> 的实例。我们不知道底层对象是什么,我们只知道我们有一个实现 IEnumerable<T> 的对象,因此我们可以使用 foreach 对其进行迭代环形。

根据我的理解,在这种情况下,无法保证从多个线程并发迭代此对象是线程安全操作。换句话说,完全有可能迭代 IEnumerable<T>来自不同线程的实例同时破坏了对象的内部状态,从而使其损坏。

我在这一点上正确吗?

IEnumerable<T>怎么样?实现Array类(class) ?它是线程安全的吗?

换句话来说,下面的代码线程安全吗? (这与上面的代码完全相同,但现在使用 foreach 循环而不是 for 循环来迭代数组)

public class UselessService 
{
private static readonly string[] Names = new [] { "bob", "alice" };

public List<int> DoSomethingUseless()
{
var temp = new List<int>();

foreach (var name in Names)
{
temp.Add(name.Length * 2);
}

return temp;
}
}

是否有任何引用说明 IEnumerable<T> .NET 基类库中的实现是实际上线程安全吗?

最佳答案

在 C# 中使用 for 循环迭代数组是线程安全操作吗?

如果您严格谈论从多个线程读取,那么对于 Array 来说这将是线程安全的。和List<T>以及 Microsoft 编写的几乎所有集合,无论您是否使用 forforeach环形。特别是在您的示例中:

var temp = new List<int>();

foreach (var name in Names)
{
temp.Add(name.Length * 2);
}

您可以根据需要跨多个线程执行此操作。他们都会从 Names 读取相同的值。很高兴。

如果您从另一个线程写入(这不是您的问题,但值得注意)

迭代ArrayList<T>for循环,它会继续读取,并且当您遇到更改的值时它会很乐意读取它们。

使用 foreach 进行迭代循环,那么这取决于实现。如果 Array 中的值通过 foreach 进行部分更改循环,它只会继续枚举并为您提供更改后的值。

List<T> ,这取决于您认为“线程安全”。如果您更关心读取准确的数据,那么它有点“安全”,因为它会在枚举中抛出异常并告诉您集合已更改。但如果您认为抛出异常不安全,那么它也不安全。

但值得注意的是,这是 List<T> 中的设计决策, there is code显式查找更改并引发异常。设计决策将我们引向下一点:

我们能否假设每个实现 IEnumerable 的集合跨多个线程读取是否安全?

大多数情况下都会如此,但不能保证线程安全的读取。原因是因为每IEnumerable需要执行 IEnumerator ,它决定如何遍历集合中的项目。就像任何类一样,您可以在其中执行任何您想要的操作,包括非线程安全的操作,例如:

  • 使用静态变量
  • 使用共享缓存读取值
  • 不努力处理集合在枚举过程中发生更改的情况
  • 等等

你甚至可以做一些奇怪的事情,比如 make GetEnumerator() 每次调用时都会返回枚举器的相同实例。这确实可能会产生一些不可预测的结果。

如果某些东西会导致不可预测的结果,我认为它不是线程安全的。任何这些事情都可能导致不可预测的结果。

您可以看到the source code for the Enumerator that List<T> uses ,所以你可以看到它没有做任何奇怪的事情,这告诉你枚举 List<T>来自多个线程是安全的。

关于c# - 在 C# 中,使用 for 循环迭代数组是线程安全操作吗?使用 foreach 循环迭代 IEnumerable<T> 怎么样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58867108/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com