2010-10-26 2 views
8

В текущей реализации CPython существует объект, известный как «GIL» или «Global Interpreter Lock». Это, по сути, мьютекс, который предотвращает одновременное выполнение двумя потоками Python кода Python. Это предотвращает возможность повреждения двух потоков в корневом состоянии интерпретатора Python, но также предотвращает совместное выполнение нескольких потоков. По существу, если я делаю это:Что такое версия C# от GIL?

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

Я не могу повредить список, потому что в любой момент времени только один из этих потоков выполняются, так как они должны держать GIL, чтобы сделать это. Теперь элементы в списке могут быть добавлены в некотором неопределенном порядке, но дело в том, что список не поврежден, и две вещи всегда будут добавлены.

Итак, теперь на C#. C# по существу сталкивается с той же проблемой, что и Python, поэтому как C# предотвращает это? Мне также будет интересно услышать историю Java, если кто ее знает.


Разъяснение: Я заинтересован в том, что происходит без явных заявлений фиксирующих, особенно в VM. Я знаю, что для примитива Java & существуют блокирующие примитивы: они существуют и на 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 мешает Пайтон «ВМ» из коррумпируются - это такое поведение, что я заинтересован в

+0

Вы можете быть заинтересованы в разделе «параллелизмом» этого [сравнения Python и Clojure] (HTTP: //www.bestinclass .dk/index.clj/2009/10/python-vs-clojure-evolving.html), для обсуждения GIL и того, как проблема параллелизма обрабатывается на языках без GIL. –

+0

Я понимаю, что это компромисс между тем, какой класс проблем будет более обременительным для решения. См. Мой ответ ниже. – pyfunc

ответ

4

Используя замок, вы могли бы сделать это:

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 для получения дополнительной информации.

+0

Я мог бы, и у Python есть подобные блокировки. Меня больше интересует случай, когда блокировки не выполняются: возможно ли повредить базовую виртуальную машину? – Thanatos

+0

@Thanatos: Не VM, а структура данных. –

+2

В результате не будет никакой гарантии, что произойдет. Это будет ** не ** повреждать состояние виртуальной машины. Однако он может испортить состояние экземпляра, на который вы вызываете методы. Если специально не указано на страницах MSDN, общее правило заключается в том, что методы экземпляра должны быть заключены в 'lock', а статические методы не должны быть заключены в' lock'. –

11

Большинство других языков, поддерживающих потоки, не имеют эквивалента Python GIL; они требуют, чтобы вы использовали мьютексы, неявно или явно.

+3

Кроме того, я бы даже не подумал о написании многопоточного кода на языке с чем-либо вроде GIL. Это похоже на мигающий неоновый знак, который говорит: «Многопоточность слишком сложна, мы сдаемся». –

+6

Я бы не стал рассматривать многопоточную программу на языке, который не может поддерживать основную структуру данных сам по себе и полагается на программистов для добавления блокировок повсюду. – piro

+2

Вы предпочли бы использовать язык, на котором невозможно совершить нечто большее, чем одно? Это не многопоточная программа. И нет, «добавление замков повсюду» - не единственная альтернатива. –

1

Это может быть полезно посмотреть на documentation for the Java equivalent класса вы обсуждаете:

Обратите внимание, что эта реализация не синхронизируется. Если несколько потоков обращаются к экземпляру ArrayList одновременно, и, по крайней мере, один из потоков изменяет список структурно, он должен быть синхронизированным извне. (Структурная модификация - это любая операция, которая добавляет или удаляет один или несколько элементов или явно изменяет размер массива поддержки; просто установка значения элемента не является структурной модификацией.) Обычно это выполняется путем синхронизации на некотором объекте, который, естественно, инкапсулирует список. Если такой объект не существует, список должен быть «завернут» с использованием метода Collections.synchronizedList.Лучше всего это сделать во время создания, чтобы предотвратить случайный несинхронизированный доступ к списку:

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

Итераторов возвращенному итераторов и ListIterator методов этого класса является отказоустойчивость быстро: если список конструктивно изменен в любое время после создания итератора, любым способом, за исключением собственных методов удаления или добавления итератора, итератор будет вызывать ConcurrentModificationException. Таким образом, перед лицом одновременной модификации итератор быстро и чисто, а не рискует произвольным, недетерминированным поведением в неопределенное время в будущем.

Обратите внимание, что неэффективное поведение итератора не может быть гарантировано, поскольку, как правило, невозможно сделать какие-либо серьезные гарантии при наличии несинхронизированной параллельной модификации. Неуправляемые итераторы бросают ConcurrentModificationException на основе наилучших усилий. Поэтому было бы неправильно писать программу, зависящую от этого исключения за ее правильность: Неудачное поведение итераторов должно использоваться только для обнаружения ошибок.

3

C# не имеет эквивалента GIL для Python.

Хотя они сталкиваются с одной и той же проблемой, их проектные цели делают их разными.

С GIL CPython гарантирует, что suche операции как добавление списка из двух потоков просты. Который также означает, что он разрешил бы только один поток для запуска в любое время. Это делает списки и словари безопасными потоками. Хотя делает работу более простой и интуитивно понятный, это делает его сложнее использовать многопоточность преимуществом для многоядерных процессоров.

Без GIL, C# делает обратное. Это гарантирует, что бремя целостности находится на разработчике программы , но позволяет использовать преимущество одновременного запуска нескольких потоков .

Согласно одному из дискуссии -

GIL в CPython является чисто дизайн выбор того большой замок против замка на объект и синхронизации, чтобы убедиться, что объекты находятся в когерентное состояние. Это состоит из компромиссов - Предоставление полной мощности многопоточности.

Было то, что большинство проблем не страдают от этого недостатка , и есть библиотеки, которые помогут вам решить эту проблему исключительно в том случае, если требуется . Это означает, что для определенного класса проблем брешь для использования мультикана - это , переданная разработчику, так что отдых может пользоваться более простым, интуитивно понятным подходом .

Примечание: Другая реализация, такая как IronPython, не имеет GIL.

+0

@ Daniel DiPaolo: Большое спасибо. Почему-то цитата не работает для меня, когда я выбираю текст и пытаюсь его процитировать. – pyfunc

+0

Странно, ну секрет в том, что это просто '>' в начале строки, которая заставляет blockquote вместо форматирования кода. Обратите внимание, что вы все равно можете форматировать код, а также в цитате блока, соответствующим образом расположив его с помощью '>' в начале строки. –

0

Большинство сложных структур данных (например, списки) могут быть повреждены при использовании без блокировки в нескольких потоках.

Поскольку изменения ссылок являются атомарными, ссылка всегда остается действительной ссылкой.

Но есть проблема при взаимодействии с критическим кодом безопасности. Поэтому любые datastructures используемых критическим кода больше всего быть один из следующих:

  • Недоступного из ненадежного кода, и заперли/правильно использовать доверенный код
  • Неизменный (String класс)
  • Скопирован перед использованием (параметров ValueType)
  • Написанные доверенный код и использует внутренний замок, чтобы гарантировать безопасное состояние

Например критический код не может доверять список доступного из ненадежного кода. Если он передается в списке, он должен создать частную копию, выполнить предварительные проверки копии, а затем работать с копией.

0

Я собираюсь взять дикую догадку на то, что вопрос действительно означает ...

В структурах данных Python в интерпретаторе испорчен, потому что Python использует форму подсчета ссылок.

Оба C# и Java используют сбор мусора, и на самом деле они do используют глобальную блокировку при выполнении полной коллекции кучи.

Данные могут быть помечены и перемещены между «поколениями» без блокировки. Но чтобы почистить все, все должно остановиться. Надеюсь, очень короткая остановка, но полная остановка.

Вот интересная ссылка на коллекцию CLR мусора в 2007:
http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry

Смежные вопросы