Python Academy · Lektion

Säker delning av data

Använd köer och lås

Lektion 4 av 413 steg

Säker delning av data är en gratis lektion i Python Academy på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Python Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Python Academy innehåller totalt 4 lektioner.

Problemet med race conditions

När flera trådar ändrar samma data kan deras operationer flätas samman och förstöra resultatet. Detta kallas en race condition. Synkroniseringsverktyg behövs för att dela data säkert.

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ås löser problemet

Ett threading.Lock ser till att endast en tråd åt gången går in i en kritisk sektion. Förvärva låset med ett with-block runt uppdateringen av den delade datan.

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 och release

Ett lås kan användas manuellt med acquire() och release(), men formen med with är säkrare eftersom låset frigörs även om ett fel inträffar.

import threading

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

Trådsäkra köer

queue.Queue är redan trådsäker. Trådar kan anropa put och get utan explicita lås, vilket gör den till det rekommenderade sättet att skicka data.

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())

Producent och konsument

Det klassiska mönstret: producenter lägger arbete i en kö med put, och konsumenter hämtar och bearbetar det med get. Kön hanterar all låsning.

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 och task_done

q.join() blockerar tills varje objekt som har lagts till med put har fått ett motsvarande anrop till task_done(). På så sätt kan huvudtråden vänta tills allt arbete är klart.

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 för återinträde

Ett vanligt Lock leder till deadlock om samma tråd försöker förvärva det två gånger. Ett threading.RLock (återinträdeslås) tillåter detta och räknar antalet förvärv.

import threading

rlock = threading.RLock()

def outer():
    with rlock:
        inner()

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

outer()

Event för signalering

Ett threading.Event låter en tråd signalera till andra. Trådar anropar wait() tills en annan tråd anropar 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()

Dela data mellan processer

Mellan processer används i stället multiprocessing.Queue. Den serialiserar objekt mellan separata minnesutrymmen.

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())

Undvik deadlock

Deadlock uppstår när trådar väntar på varandras lås för alltid. Undvik detta genom att alltid förvärva flera lås i samma ordning överallt.

import threading

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

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

safe()

Föredra köer framför lås

När det är möjligt bör meddelandeöverföring med köer föredras framför delat, förändringsbart tillstånd som skyddas av lås. Det är lättare att förstå och leder till betydligt färre fel.

import queue

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

Snabbkontroll

Testa förståelsen av säker datadelning.

Sammanfattning

Ni har lärt Er att dela data säkert:

  • Race conditions kan förstöra oskyddat delat tillstånd.
  • Lock och RLock skyddar kritiska sektioner.
  • queue.Queue är trådsäker; använd multiprocessing.Queue mellan processer.
  • Event signalerar mellan trådar; en konsekvent låsordning förhindrar deadlock.

Nästa kurs: köra externa program med subprocess.

Gratis att börja

Lär dig Python med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
76
Lektioner
320

Vanliga frågor

Är lektionen ”Säker delning av data” gratis?

Ja – hela texten till ”Säker delning av data” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Python Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Python Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Säker delning av data”?

Använd köer och lås Ni övar på Python Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Python Academy?

Du behöver inga förkunskaper. Utbildningen i Python Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Säker delning av data”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Python Academy-lektionen?

Ja. Varje Python Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Trådar och GIL
  2. ThreadPoolExecutor
  3. Grunderna i multiprocessing
  4. Säker delning av data
← Tillbaka till Python Academy