GIL 的 C# 版本是什么?

发布于 2024-09-29 00:09:20 字数 1162 浏览 11 评论 0 原文

在当前的 CPython 实现中,有一个称为“GIL”或“全局解释器锁”的对象。它本质上是一个互斥锁,可以防止两个 Python 线程同时执行 Python 代码。这可以防止两个线程破坏 Python 解释器的状态,同时也可以防止多个线程真正一起执行。本质上,如果我这样做:

# Thread A
some_list.append(3)
# Thread B
some_list.append(4)

我不能破坏列表,因为在任何给定时间,只有其中一个线程正在执行,因为它们必须持有 GIL 才能执行此操作。现在,列表中的项目可能会以某种不确定的顺序添加,但重点是列表不会损坏,并且总是会添加两件事。

那么,现在转向 C#。 C# 本质上面临着与 Python 相同的问题,那么,C# 如何防止这种情况发生呢?如果有人知道的话,我也有兴趣听听 Java 的故事。


说明:我对没有显式锁定语句时会发生什么感兴趣,尤其是对于虚拟机。我知道 Java 和 Java 都存在锁定原语。 C# - 它们也存在于 Python 中:GIL 不用于多线程代码,只是为了保持解释器的理智。我对上面的直接等价物感兴趣,所以,在 C# 中,如果我记得足够的话...:-)

List<String> s;
// Reference to s is shared by two threads, which both execute this:
s.Add("hello");
// State of s?
// State of the VM? (And if sane, how so?)

这是另一个例子:

class A
{
    public String s;
}
// Thread A & B
some_A.s = some_other_value;

// some_A's state must change: how does it change?
// Is the VM still in good shape afterwards?

我不想编写糟糕的 C# 代码,我理解 lock< /代码> 语句。即使在 Python 中,GIL 也不会为您提供神奇的多线程代码:您仍然必须锁定共享资源。但是 GIL 可以防止 Python 的“VM”被损坏——我对这种行为感兴趣。

In the current implementation of CPython, there is an object known as the "GIL" or "Global Interpreter Lock". It is essentially a mutex that prevents two Python threads from executing Python code at the same time. This prevents two threads from being able to corrupt the state of the Python interpreter, but also prevents multiple threads from really executing together. Essentially, if I do this:

# Thread A
some_list.append(3)
# Thread B
some_list.append(4)

I can't corrupt the list, because at any given time, only one of those threads are executing, since they must hold the GIL to do so. Now, the items in the list might be added in some indeterminate order, but the point is that the list isn't corrupted, and two things will always get added.

So, now to C#. C# essentially faces the same problem as Python, so, how does C# prevent this? I'd also be interested in hearing Java's story, if anyone knows it.


Clarification: I'm interested in what happens without explicit locking statements, especially to the VM. I am aware that locking primitives exist for both Java & C# - they exist in Python as well: The GIL is not used for multi-threaded code, other than to keep the interpreter sane. I am interested in the direct equivalent of the above, so, in C#, if I can remember enough... :-)

List<String> s;
// Reference to s is shared by two threads, which both execute this:
s.Add("hello");
// State of s?
// State of the VM? (And if sane, how so?)

Here's another example:

class A
{
    public String s;
}
// Thread A & B
some_A.s = some_other_value;

// some_A's state must change: how does it change?
// Is the VM still in good shape afterwards?

I'm not looking to write bad C# code, I understand the lock statements. Even in Python, the GIL doesn't give you magic-multi-threaded code: you must still lock shared resources. But the GIL prevents Python's "VM" from being corrupted - it is this behavior that I'm interested in.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

权谋诡计 2024-10-06 00:09:20

大多数支持线程的其他语言都没有相当于 Python GIL 的工具;它们要求您隐式或显式地使用互斥锁。

Most other languages that support threading don't have an equivalent of the Python GIL; they require you to use mutexes, either implicitly or explicitly.

勿忘初心 2024-10-06 00:09:20

使用锁,您可以执行以下操作:

lock(some_list)
{
    some_list.Add(3);
}

在线程 2 中:

lock(some_list)
{
    some_list.Add(4);
}

lock 语句确保 lock 语句内的对象,在本例中为 some_list ,一次只能由一个线程访问。请参阅 http://msdn.microsoft.com/en-us /library/c5kehkcz(VS.80).aspx 了解更多信息。

Using lock, you would do this:

lock(some_list)
{
    some_list.Add(3);
}

and in thread 2:

lock(some_list)
{
    some_list.Add(4);
}

The lock statement ensures that the object inside the lock statement, some_list in this case, can only be accessed by a single thread at a time. See http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx for more information.

孤寂小茶 2024-10-06 00:09:20

C# 没有相当于 Python 的 GIL。

虽然他们面临同样的问题,但他们的设计目标使他们
不同。

使用 GIL,CPython 确保诸如附加列表之类的操作
来自两个线程很简单。其中还
意味着它只允许一个
线程随时运行。这
使列表和字典线程安全。虽然这使得工作
更简单直观
,它使得
更难利用多线程
多核优势。

如果没有 GIL,C# 则执行相反的操作。 它确保完整性的责任由开发者承担
计划,但允许您采取
运行多线程的优点
同时。


根据其中一项讨论 -

CPython 中的 GIL 纯粹是一种设计选择
大锁与每个对象一个锁
和同步以确保对象保持一致状态。
这包括一个权衡——放弃全部权力
多线程。

大多数问题都没有这个缺点
并且有一些库可以帮助您专门解决这个问题
必需的。
这意味着对于某一类问题,利用
多核是
传递给开发者,让休息可以享受更简单、直观
方法。

注意:其他实现(例如 IronPython)没有 GIL。

C# does not have an equivalent of GIL to Python.

Though they face the same issue, their design goals make them
different.

With GIL, CPython ensures that suche operations as appending a list
from two threads is simple. Which also
means that it would allow only one
thread to run at any time. This
makes lists and dictionaries thread safe. Though this makes the job
simpler and intuitive
, it makes it
harder to exploit the multithreading
advantage on multicores.

With no GIL, C# does the opposite. It ensures that the burden of integrity is on the developer of the
program
but allows you to take
advantage of running multiple threads
simultaneously.

As per one of the discussion -

The GIL in CPython is purely a design choice of having
a big lock vs a lock per object
and synchronisation to make sure that objects are kept in a coherent state.
This consist of a trade off - Giving up the full power of
multithreading.

It has been that most problems do not suffer from this disadvantage
and there are libraries which help you exclusively solve this issue when
required.
That means for a certain class of problems, the burden to utilize the
multicore is
passed to developer so that rest can enjoy the more simpler, intuitive
approach.

Note: Other implementation like IronPython do not have GIL.

千纸鹤 2024-10-06 00:09:20

查看Java 等效文档可能会有所帮助您正在讨论的班级:

请注意,此实现不是同步的。如果多个线程同时访问 ArrayList 实例,并且至少有一个线程在结构上修改了列表,则必须在外部同步。 (结构修改是添加或删除一个或多个元素,或显式调整后备数组大小的任何操作;仅设置元素的值不是结构修改。)这通常是通过同步某些自然封装了结构的对象来完成的。列表。如果不存在这样的对象,则应使用 Collections.synchronizedList 方法。最好在创建时完成此操作,以防止意外地不同步访问列表:

List list = Collections.synchronizedList(new ArrayList(...));

此类的迭代器和 listIterator 方法返回的迭代器是快速失败:如果在创建迭代器后的任何时间以任何方式对列表进行结构修改,除了通过迭代器自己的删除或添加方法时,迭代器将抛出 ConcurrentModificationException< /代码>。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒任意、非确定性行为的风险。

请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在不同步并发修改的情况下不可能做出任何硬保证。快速失败迭代器会尽力抛出ConcurrentModificationException。因此,编写依赖于此异常来确保其正确性的程序是错误的:迭代器的快速失败行为应该仅用于检测错误

It may be instructive to look at the documentation for the Java equivalent of the class you're discussing:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:

List list = Collections.synchronizedList(new ArrayList(...));

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

定格我的天空 2024-10-06 00:09:20

大多数复杂的数据结构(例如列表)在不锁定多个线程的情况下使用时可能会被损坏。

由于引用的更改是原子的,因此引用始终保持有效引用。

但与安全关键代码交互时存在问题。因此,关键代码使用的任何数据结构大多是以下之一:

  • 不可从不受信任的代码访问,并由受信任的代码正确锁定/使用
  • 不可变(String 类)
  • 在使用前复制(值类型参数)
  • 用受信任的代码编写并使用内部锁定来保证安全状态

例如,关键代码不能信任可从不受信任的代码访问的列表。如果它在列表中传递,它必须创建一个私有副本,对该副本进行先决条件检查,然后对该副本进行操作。

Most complex datastructures(for example lists) can be corrupted when used without locking in multiple threads.

Since changes of references are atomic, a reference always stays a valid reference.

But there is a problem when interacting with security critical code. So any datastructures used by critical code most be one of the following:

  • Inaccessible from untrusted code, and locked/used correctly by trusted code
  • Immutable (String class)
  • Copied before use (valuetype parameters)
  • Written in trusted code and uses internal locking to guarantee a safe state

For example critical code cannot trust a list accessible from untrusted code. If it gets passed in a List, it has to create a private copy, do it's precondition checks on the copy, and then operate on the copy.

凹づ凸ル 2024-10-06 00:09:20

我将大胆猜测一下这个问题的真正含义……

在 Python 中,解释器中的数据结构会被损坏,因为 Python 使用了一种引用计数形式。

C# 和 Java 都使用垃圾收集,事实上,它们在执行完整堆收集时确实使用全局锁。

数据可以在“代”之间进行标记和移动,而无需锁定。但要真正清理干净,一切都必须停止。希望这是一个非常短暂的停留,但也是一个完整的停留。

以下是截至 2007 年有关 CLR 垃圾回收的有趣链接:
http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD !1104.entry

I'm going to take a wild guess at what the question really means...

In Python data structures in the interpreter get corrupted because Python is using a form of reference counting.

Both C# and Java use garbage collection and in fact they do use a global lock when doing a full heap collection.

Data can be marked and moved between "generations" without a lock. But to actually clean it up everything must come to a stop. Hopefully a very short stop, but a full stop.

Here is an interesting link on CLR garbage collection as of 2007:
http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文