我有一个 IronPython script,它使用 TPL 和 Parallel.ForEach 来处理使用多线程的文件。在 C# 中,我可以使用 Interlocked.Add 和 Interlocked.Increment 在原子线程安全操作中更改全局变量,但这在 IronPython 中不起作用,因为 integers are immutable 。我目前有一个简单的 Results 类,它将一些变量存储为静态成员,用于跟踪多线程操作的结果。更改多个值时,我可以使用 .NET Monitor 类锁定该类以确保更新是线程安全的,但是如果我只想更新单个变量(例如只是增加 Results.Files),这似乎是很多开销。
我的问题是,是否有更好的方法以类似于 Interlocked.Increment 工作方式的线程安全或原子方式增加 IronPython 中的 Results.Files 等单个静态成员变量?或者,是否有任何内置于 python 或 .NET 框架中的线程安全计数器可以用来代替基本整数?
class Results:
Files = 0
Lines = 0
Tolkens = 0
@staticmethod
def Add(intFiles, intLines, intTolkens):
#Use the System.Threading.Monitor class to ensure addition is thread safe
Monitor.Enter(Results)
Results.Files += intFiles
Results.Lines += intLines
Results.Tolkens += intTolkens
Monitor.Exit(Results) #Finish thread safe code
最佳答案
看起来 python 的方法是使用 multiprocessing.Value 对象,默认情况下,只要访问该对象,就会锁定该对象。遗憾的是,多处理类没有内置在 IronPython 中,因为它基于 CTypes。然而,我确实找到了一种使用 Interlocked 类和对 CLR 对象的引用来做到这一点的方法:
import clr
from System.Threading import Interlocked
refInt = clr.Reference<int>(5) #Create a reference to an integer
#refInt = <System.Int32 object at 0x0000000000000049 [5]>
#refInt.Value = 5
Interlocked.Increment(refInt) #Returns 6 and refInt now points to a new integer
#refInt = <System.Int32 object at 0x000000000000004A [6]>
#refInt.Value = 6
在这种情况下,您可以使用所有 Interlocked 方法来添加、比较、交换、递增和读取 refInt 对象。您也可以直接获取或设置 refInt.Value,但只有 Interlocked 方法是线程安全的。还有 Interlocked 方法 will NOT throw an overflow exception (它只会静默包装),因此请确保您选择的数据类型足够大,不会溢出。
关于.net - 如何在 IronPython 中原子地增加静态成员?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2255461/