İş parçacığı güvenli işlemler için bağlam yöneticisi, bir kaynağın (örneğin bir dosya veya paylaşılan veriler) kilidinin her zaman doğru bir şekilde serbest bırakılmasını garanti eder; bu, bir istisna oluşsa bile geçerlidir. Bu, birden fazla iş parçacığının aynı verilere aynı anda erişebileceği çok parçacıklı programlar için önemlidir.
Soru tarihi:
İş parçacığı güvenliği ihtiyacı çok parçacıklı hesaplama uygulanmaya başlandığından beri var. Python'da, 2.5 sürümünden itibaren, kaynaklarla çalışmayı standartlaştıran bir bağlam yöneticisi protokolü eklendi. İş parçacıkları için bu, kilitlerin basit ve güvenilir bir şekilde yönetilmesi anlamına gelir.
Sorun:
Kilitlerin manuel yönetiminde (acquire()/release()) release çağrısını unutmak kolaydır, özellikle bir istisna yakalandığında. Bu, ölü blokajlara (deadlock) yol açar. Bağlam yöneticisi böyle hatalardan kaçınmaya yardımcı olur.
Çözüm:
Yerleşik threading.Lock kullanarak veya __enter__ ve __exit__ sihirli yöntemlerini uygulayarak kendi bağlam yöneticinizi oluşturun.
Kod örneği:
import threading lock = threading.Lock() # Standart yol with lock: # Kritik bölüm print("İş parçacığı güvenli işlemi gerçekleştiriliyor") # Kendi bağlam yöneticiniz class SafeLock: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() return self def __exit__(self, exc_type, exc_val, exc_tb): self.lock.release() with SafeLock(lock): print("Kişisel kilit yöneticisi çalışıyor!")
Ana özellikler:
with ifadesini kullanmanızı sağlar.Bir sınıfın bağlam yöneticisi olması için her iki yöntemi (enter, exit) uygulamak zorunda mıyım?
Hayır, with ifadesinde çalışması için yalnızca __exit__ uygulamak yeterlidir, ancak genellikle iç durumu kullanmak için __enter__ gerekir. Ancak, __enter__ olmadan as ile nesne/kaynak döndürmek imkansızdır, bu nedenle with sözdizimi için her iki yöntem de gereklidir.
with lock kullanıyorsanız, release'i en son çağırmak gerekir mi?
Hayır, with ifadesi ile bunu yapmanıza gerek yoktur: kilit, bir bloktan çıkıldığında otomatik olarak serbest bırakılır, hatta bir istisna oluşsa bile. Bu, bağlam yöneticilerinin en büyük avantajıdır.
Aynı kilidi farklı with ifadeleri ile aynı anda birden fazla iş parçacığında kullanmak mümkün mü?
Evet, bu, kilidin mantığı ile sağlanmıştır: başka bir iş parçacığı tarafından edinilmiş bir kilidi alma girişiminde bulunan mevcut iş parçacığı, kaynak serbest bırakılana kadar engellenir. Ancak, kritik bölümlerin yanlış düzenlenmesi, kodun farklı yerlerinde edinim sırası farklı olduğu için ölü blokajlara yol açabilir.
try/finally veya with olmadan acquire/release kullanmak (release'i atlamak).unlock kullanmak veya çift acquire yapmak.Geliştirici manuel olarak yazıyor:
lock.acquire() # Kritik bölüm if bir şey_hatalı_ise: return # release'i unuttuk! lock.release()
Artılar:
Eksiler:
release'in atlanması çok basittir, bu da ölü blokaja neden olur ve program "takılır".with kullanılır:
with lock: # Kritik bölüm if bir şey_hatalı_ise: return
Artılar:
return ve istisnalardan bağımsız olarak her zaman doğru kilit serbest bırakma.Eksiler:
within içinde kritik bir işlemin olduğunu hemen anlamayabilir (kodun bağlamını dikkate almak gerekecektir).