2010-02-09 1 views

ответ

39

Вам необходимо реализовать свою собственную блокировку для всех общих переменных, которые будут изменены в Python. Вам не нужно беспокоиться о чтении из переменных, которые не будут изменены (т. Е. Одновременные чтения в порядке), поэтому неизменяемые типы (frozenset, tuple, str) являются , вероятно, безопасными, но это не помешает. Для вещей, которые вы собираетесь менять - list, set, dict, и большинство других объектов, у вас должен быть свой собственный механизм блокировки (в то время как операции на месте в порядке на большинстве из них, потоки могут привести к супер-неприятным ошибкам - вы можете также реализовать блокировку, это довольно легко).

Кстати, я не знаю, если вы знаете это, но замок очень легко в Python - создать объект threading.lock, а затем вы можете приобрести/снять его так:

import threading 
list1Lock = threading.Lock() 

with list1Lock: 
    # change or read from the list here 
# continue doing other stuff (the lock is released when you leave the with block) 

В Python 2.5, do from __future__ import with_statement; Python 2.4 и до этого нет, так что вы хотите поставить приобретаемой()/Release() вызывает в try:...finally: блоков:

import threading 
list1Lock = threading.Lock() 

try: 
    list1Lock.acquire() 
    # change or read from the list here 
finally: 
    list1Lock.release() 
# continue doing other stuff (the lock is released when you leave the with block) 

Some very good information about thread synchronization in Python.

+12

Я считаю, что для тех, кто раньше не использовал блокировки потоков, следует отметить, что блокировка (в вашем примере, 'list1Lock') должна быть * совместно используемой * между потоками, чтобы она работала правильно. Два независимых замка, по одному для каждой нити, ничего не запирали, просто добавляли глупые накладные расходы. – tzot

+0

Не должно быть: со списком1Lock: # Сделайте что-нибудь –

+0

@ slack3r Хороший звонок! –

3

Они потокобезопасны, если вы не отключите GIL в коде C для потока.

+5

Это деталь реализации CPython, на которую вы не должны включать реле. Вероятно, это произойдет в будущем, а другие реализации этого не будут иметь. –

+0

Георг - этот аспект python меня интересует. Не обращайте внимания на все ошибки, которые выпадают из java-программ, когда 8 ядер становятся обычными на рабочем столе. Что происходит, когда GIL удаляется, и многопоточные приложения python неожиданно работают на 8 ящиках? – Ben

+3

Не должно никого напугать, если они не притворяются, что их код является потокобезопасным, когда это явно не так. :) – Kylotan

7

Да, но вы все равно должны быть осторожны, конечно

Например:

Если две нити мчитесь pop() из списка только один пункт, один поток будет получить деталь успешно и другие получат IndexError

код, как это не поточно-

if L: 
    item=L.pop() # L might be empty by the time this line gets executed 

Вы должны Wr ite это как это

try: 
    item=L.pop() 
except IndexError: 
    # No items left 
+5

Я хочу, чтобы pop() был потокобезопасным, но я не могу найти этот факт в документации. Может кто-нибудь помочь мне исправить это требование, прежде чем я возьму его как Евангелие? –

+0

Действительно? list.pop() не является потокобезопасным? Я видел еще одну статью, утверждающую обратное. http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm –

+0

@ Zhongjun'Mark'Jin он сказал, что это потокобезопасно .. но это не значит вам не нужно учитывать другие потоки. Если один поток выталкивает последний элемент, а затем пытается использовать другой поток, он получит IndexError, как он говорит. – fantabolous