Python Academy · leksjon

Trygg deling av data

Bruk køer og låser

Leksjon 4 av 413 trinn

Trygg deling av data er en gratis leksjon i Python Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Python Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Python Academy inneholder totalt 4 leksjoner.

Problemet med kappløpstilstander

Når flere tråder endrer de samme dataene, kan operasjonene deres flettes inn i hverandre og ødelegge resultatet. Dette kalles en kappløpstilstand. Vi trenger synkroniseringsverktøy for å dele data på en trygg måte.

import threading

counter = 0

def bump():
    global counter
    for _ in range(100000):
        counter += 1

ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter (may be < 200000):', counter)

Låsen til unnsetning

En threading.Lock sørger for at bare én tråd om gangen går inn i en kritisk seksjon. Skaff låsen med en with-blokk rundt oppdateringen av de delte dataene.

import threading

counter = 0
lock = threading.Lock()

def bump():
    global counter
    for _ in range(100000):
        with lock:
            counter += 1

ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter:', counter)

acquire og release

En lås kan brukes manuelt med acquire() og release(), men with-formen er tryggere fordi den frigir låsen selv om det oppstår en feil.

import threading

lock = threading.Lock()
lock.acquire()
try:
    print('inside critical section')
finally:
    lock.release()
print('released')

Trådsikre køer

Klassen queue.Queue er allerede trådsikker. Tråder kan bruke put og get uten eksplisitte låser, noe som gjør den til den foretrukne måten å overføre data på.

import queue, threading

q = queue.Queue()

def producer():
    for i in range(3):
        q.put(i)

t = threading.Thread(target=producer)
t.start()
t.join()
while not q.empty():
    print('got', q.get())

Produsent og konsument

Det klassiske mønsteret er at produsenter legger arbeid i en kø med put, mens konsumenter henter og behandler det med get. Køen håndterer all låsing.

import queue, threading

q = queue.Queue()
results = []

def consumer():
    while True:
        item = q.get()
        if item is None:
            break
        results.append(item * 10)
        q.task_done()

t = threading.Thread(target=consumer)
t.start()
for i in range(3):
    q.put(i)
q.put(None)
t.join()
print(results)

join og task_done

q.join() blokkerer til hvert element som er lagt inn med put, har fått et tilsvarende kall til task_done(). Dermed kan hovedtråden vente til alt arbeidet er ferdig.

import queue, threading

q = queue.Queue()

def worker():
    while True:
        item = q.get()
        q.task_done()

threading.Thread(target=worker, daemon=True).start()
for i in range(5):
    q.put(i)
q.join()
print('all items processed')

RLock for reentrant bruk

En vanlig Lock fører til deadlock hvis den samme tråden prøver å skaffe den to ganger. En threading.RLock (reentrant lås) tillater dette ved å telle antall ganger låsen er skaffet.

import threading

rlock = threading.RLock()

def outer():
    with rlock:
        inner()

def inner():
    with rlock:
        print('re-entered safely')

outer()

Event for signalering

En threading.Event lar én tråd signalisere til andre. Tråder kaller wait() til en annen tråd kaller set().

import threading

start = threading.Event()

def worker():
    start.wait()
    print('go!')

t = threading.Thread(target=worker)
t.start()
print('setting event')
start.set()
t.join()

Deling mellom prosesser

Mellom prosesser bruker du i stedet multiprocessing.Queue. Den serialiserer objekter mellom separate minneområder.

import multiprocessing as mp

def producer(q):
    for i in range(3):
        q.put(i * i)

if __name__ == '__main__':
    q = mp.Queue()
    p = mp.Process(target=producer, args=(q,))
    p.start()
    p.join()
    while not q.empty():
        print('received', q.get())

Unngå deadlock

Deadlock oppstår når tråder venter på hverandres låser for alltid. Unngå dette ved alltid å skaffe flere låser i samme rekkefølge overalt.

import threading

lock_a = threading.Lock()
lock_b = threading.Lock()

def safe():
    with lock_a:
        with lock_b:
            print('acquired in consistent order')

safe()

Foretrekk køer fremfor låser

Når det er mulig, bør du foretrekke meldingsutveksling med køer fremfor delt, muterbar tilstand som beskyttes av låser. Det er enklere å forstå og gir langt færre feil.

import queue

q = queue.Queue()
for word in ['safe', 'simple', 'clear']:
    q.put(word)
while not q.empty():
    print(q.get())

Kort test

Test forståelsen din av trygg datadeling.

Oppsummering

Du har lært å dele data på en trygg måte:

  • Kappløpstilstander kan ødelegge delt tilstand som ikke er beskyttet.
  • Lock og RLock beskytter kritiske seksjoner.
  • queue.Queue er trådsikker; bruk multiprocessing.Queue mellom prosesser.
  • Event signaliserer mellom tråder, og en konsekvent rekkefølge for låsing unngår deadlock.

Neste kurs: kjøre eksterne programmer med subprocess.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
76
Leksjoner
320

Ofte stilte spørsmål

Er leksjonen «Trygg deling av data» gratis?

Ja – hele teksten i «Trygg deling av data» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Python Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Python Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Trygg deling av data»?

Bruk køer og låser Du øver på Python Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Python Academy?

Ingen tidligere erfaring er nødvendig. Python Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «Trygg deling av data»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Python Academy-leksjonen?

Ja. Alle Python Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Tråder og GIL
  2. ThreadPoolExecutor
  3. Grunnleggende om multiprocessing
  4. Trygg deling av data
← Tilbake til Python Academy