[python] multithreading & mutable sequence types

Radek Kanovsky rk na dat.cz
Pondělí Říjen 25 13:49:12 CEST 2004


On Mon, Oct 25, 2004 at 11:02:52AM +0200, Marek Schmidt wrote:

> Dobrý den,
> 
> s Pythonem teprve začínám a tak ještě nejsem příliž zběhlý v hledání 
> odpovědí na otázky... snažil jsem se... :-)
> 
> Jsou operace s pythonovským seznamem thread-safe?

Obecne nejsou zadne operace v pythonu thread-safe, ale konkretne append
a pop nad seznamem jo, protoze jsou implementovane v C a behem jejich
vykonavani je zamceny Global Interpreter Lock (GIL) a nikdo druhy by
nemel mit sanci neco s tim seznamem udelat. Funkce/metody psane v C
mohou GIL explicitne odemknout, pokud na neco cekaji (typicky na I/O),
ale tyto dve to nedelaji. Nicmene asi neni dobre na to spolehat a navic
to urcite plati jenom CPythonu. Jython, IronPython a dalsi odrudy se
mohou chovat odlisne (neznam).

> Potřebuji udělat něco takového:
> 
> class KnightWhoSayNi(threading.Thread):
>   def __init__(self):
>     ...
>     self.semafor = threading.Semaphore(0)
>     self.queue = []
> 
>   def queueSayNi(self, target):
>     self.queue.append(target)
>     self.semafor.release()
> 
>   def run(self):
>     while True:
>        self.semafor.acquire()
>        target = self.queue.pop(0)
> 
>        sayNiToTarget(target)
> 
> 
> queueSayNi se bude volat z jiných threadů. Můj dotaz pochopitelně zní: 
> Je bezpečné to udělat takto a nebo je nutné operace s queue uzavřít mezi 
> lock.acquire a lock.release? (případně, nejde to vše udělat nějak úplně 
> jinak a lépe? :-)

Ja bych na tohle pouzil asi threading.Condition. Moc se mne nelibi
ono acquire/release v ruznych metodach.
    
    [...]

    def __init__ (self) :
        ....
        self.cond = threading.Condition()
        self.queue = []

    def queueSayNi(self, target):
        self.cond.acquire()
        self.queue.append(target)
        self.cond.notify()
        self.cond.release()
 
    def run(self):
        while True:
            self.cond.acquire()
            while not self.queue :
                self.cond.wait()
            target = self.queue.pop(0)
            self.cond.release()
            sayNiToTarget(target)


Pokud je seznam prazdny, odemce cond.wait() zamek a ceka na cond.notify().
cond.notify() je volano po vlozeni noveho prvku a to vzbudi cekajici
cond.wait(). Po navratu z cond.wait() je zamek opet zamceny.

Ni! Ni! Ni! Ni! Ni! Ni!

RadekK



Další informace o konferenci Python