C#的GIL是什么?
在当前的CPython实现中,有一个叫做“GIL”或者“全局解释器锁”的对象。简单来说,它就像一个锁,防止两个Python线程同时执行Python代码。这样做是为了避免两个线程同时改变Python解释器的状态,但也因此限制了多个线程真正一起执行的能力。换句话说,如果我这样做:
# Thread A
some_list.append(3)
# Thread B
some_list.append(4)
我不会破坏这个列表,因为在任何时刻,只有一个线程在执行代码,因为它们必须持有GIL才能运行。虽然列表中的项目可能会以某种不确定的顺序被添加,但关键是列表不会被破坏,并且总会有两个项目被添加。
接下来谈谈C#。C#面临着和Python类似的问题,那么C#是怎么解决这个问题的呢?如果有人知道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的“虚拟机”被破坏——这就是我感兴趣的行为。
6 个回答
C#没有像Python那样的全局解释器锁(GIL)。
虽然它们面临同样的问题,但设计目标不同。
有了GIL,CPython确保了像从两个线程向列表添加元素这样的操作变得简单。这也意味着在任何时候只能有一个线程在运行。这使得列表和字典是线程安全的。虽然这样做让事情变得更简单和直观,但也让在多核处理器上利用多线程的优势变得更困难。
没有GIL的C#则正好相反。它确保了程序的完整性责任在开发者身上,但允许你同时运行多个线程。
根据讨论中的一个观点 -
CPython中的GIL纯粹是一个设计选择,选择了一个大锁而不是每个对象一个锁,并通过同步来确保对象保持一致的状态。这是一个权衡——放弃了多线程的全部能力。
大多数问题并不会受到这个缺点的影响,并且有一些库可以帮助你在需要时专门解决这个问题。这意味着对于某些类型的问题,利用多核的责任转移给了开发者,这样其他人就可以享受更简单、直观的方法。
注意:其他实现,比如IronPython,是没有GIL的。
使用锁的时候,你可以这样做:
lock(some_list)
{
some_list.Add(3);
}
然后在第二个线程里:
lock(some_list)
{
some_list.Add(4);
}
lock
语句的作用是确保在这个语句里的对象,比如这里的 some_list
,一次只能被一个线程访问。想了解更多信息,可以查看这个链接:http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx。
大多数其他支持多线程的编程语言没有像Python的全局解释器锁(GIL)这样的东西;它们需要你使用互斥锁,无论是隐式的还是显式的。