Vraag python dictionary is thread safe?


Sommigen verklaarden dat python dictionary thread safe is. Betekent dit dat ik de items in een woordenboek kan of kan wijzigen terwijl er overheen wordt nagedacht?


23
2017-07-29 01:07


oorsprong


antwoorden:


De twee concepten zijn compleet anders. De veiligheid van de draad betekent dat twee threads hetzelfde object niet op hetzelfde moment kunnen wijzigen, waardoor het systeem in een inconsistente staat blijft.

Dat gezegd hebbende, je kunt een woordenboek niet aanpassen terwijl je er overheen leest. Zie de documentatie..

Het woordenboek p mag tijdens herhaling niet worden gemuteerd. Het is veilig (sinds Python 2.1) om   wijzig de waarden van de toetsen terwijl u over het woordenboek herhaalt, maar alleen zolang als het   aantal toetsen verandert niet.


28
2017-07-29 01:16



De andere antwoorden waren al goed gericht op wat je feitelijke vraag blijkbaar is:

Betekent dit dat ik wel of niet kan wijzigen?   de items in een woordenboek terwijl   iteratie erover?

door uit te leggen dat threadveiligheid niets met het probleem te maken heeft, en in ieder geval, nee, je kunt een dictaat niet aanpassen terwijl je er overheen zit.

Maar de titel van uw vraag is over draadveiligheid, en je begint met:

Sommigen verklaarden dat python-woordenboek dat is   draad veilig

Ik weet niet wie de "sommigen" zijn, maar als ze dat beweren (in plaats van dat je verkeerd begrijpt wat ze deden ;-) zonder zware kwalificaties, hebben ze het mis.

Sommige bewerkingen, die de set sleutels in het dictaat niet veranderen, zijn thread-safe in de huidige CPython-implementaties - maar je moet niet reken hierop, tenzij je de Python-versie waaronder je code draait strikt controleert, omdat een dergelijke threadveiligheid niet wordt gegarandeerd door de taalspecificatie van Python en daarom andere implementaties, waaronder toekomstige versies van CPython, deze mogelijk niet aanbieden.

Als elke thread alleen het dict leest (indexeert, lus, enz.) En geen thread een opdracht of verwijdering uitvoert, dan is die situatie veilig in de huidige CPython-implementaties; in feite, als een thread een nieuwe waarde toewijst aan een sleutel die al aanwezig was, is dat ook thread safe (andere threads kunnen de vorige waarde voor die sleutel zien, of de volgende, afhankelijk van hoe de threads getimed zijn, maar er zal geen crash zijn, geen impasse, en geen schijn van gekke waarden uit het niets, in de huidige CPython-implementaties).

Een bewerking zoals d[k] += 1 (ervan uitgaande dat k eerder aanwezig was, en de waarde een getal) is niet correct draad veilig (meer dan andere gevallen van +=!) omdat het kan worden gezien als d[k] = d[k] + 1 - het macht gebeuren dat twee threads in een race-conditie zowel de oude waarde van lezen d[k], verhoog het dan met één, en sla dezelfde nieuwe waarde op in de sleuf ... dus het totale effect is om het alleen met één te verhogen, en niet met twee, zoals normaal zou gebeuren.

Terug naar je andere vraag ... "alleen het dictaat lezen", ennieuwe waarden toewijzen aan sleutels die al bestonden in het dictaat, zijn ook de dingen die u kunt doen in het lichaam van een lus die op het dictaat wordt herhaald - u kunt de reeks toetsen in het dictaat niet wijzigen (u kunt niet toevoegen om het even welke sleutel, en verwijder geen toetsen), maar de specifieke bewerking van het instellen van een nieuwe waarde voor een bestaande sleutel is toegestaan. De toegestane bewerkingen in dit geval omvatten de += dat zou problematisch zijn in een threading-situatie. Bijvoorbeeld:

>>> d = dict.fromkeys(range(5), 0)
>>> for k in d: d[k] += 1
... 
>>> d
{0: 1, 1: 1, 2: 1, 3: 1, 4: 1}

en deze gedrag wordt gegarandeerd door de gestandaardiseerde semantiek van Python, dus verschillende implementaties van de taal zouden het allemaal moeten behouden.


59
2017-07-29 02:04



Nee. Recente versie van python genereert een uitzondering als u probeert een woordenboek te herhalen dat de grootte tussen iteraties heeft gewijzigd.

>>> d={'one':1, 'two':2}
>>> for x in d:
...    d['three']=3
...    print x
...
two
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Merk op dat u geen threads hoeft te gebruiken om dit te zien


14
2017-07-29 01:17