Senkronizasyon Aracı Olarak Dosyalar
Zaman zaman, yazdığımız programlarda yapılacak işi, multi-threading veya multi-processing kullanarak paralel olarak gerçekleştirme ihtiyacı hissederiz. Bu gibi durumlarda, aynı anda çalışmakta olan işlemleri veya iş parçacıklarını (thread) belirli bir senkronizasyon içinde çalıştırmamız gerekir. Bu senkronizasyonu sağlamak için, kullandığımız programlama dilinin bize sağladığı araçları kullanırız.
Geçmişte, python ile yazdığım bir program ile, internetteki çeşitli kaynaklardan binlerce json belgesi indirmem gerekti. Python'daki threading ve multi-processing modüllerini kullanmak yerine, değişik birşey yapmak istedim. Bu yazıda kısaca, aynı anda çalışan işlemleri senkronize etmek için kullandığım metotdan bahsedeceğim.
Python'da dosya açarken, standard open
fonksiyonunun yanında, os
modülü içindeki
open
fonksiyonunu da kullanabiliyoruz. os
modülü içindeki open
fonksiyonu ile
dosya açarken, daha fazla kontrole sahibiz. Bunun için, os.open
fonksiyonunun ikinci
argümanına, dosya açmak için gerekli seçenekleri, bitwise or (|) ile birleştirerek belirtiyoruz. Burada
göstereceğim yöntem için gerekli olan argümanlar os.O_CREAT
ve os.O_EXCL
. Bu iki
argüman birlikte kullanıldığında, oluşturmaya çalıştığımız dosya zaten varsa, dosya açma
işlemi başarısız oluyor. Bunu nasıl kullanabileceğimizi görmek için, aşağıdaki örnek
kodları inceleyebiliriz.
Yukarıdaki kodları incelerseniz, multiprocessing
ve threading
modüllerinden
hiç bahsedilmediğini göreceksiniz. İşin güzelliği de burada. Yukarıdaki programı
yanyana birkaç kere çalıştırırsanız, herhangi bir işlemin indirmeye başladığı
dosyayı bir diğeri indirmeyecektir. İşin püf noktası şöyle; tüm işlemler, bir
linki indirmeye başlamadan önce, o linkin daha önce indirilmeye başlayıp
başlamadığını anlamak için, dosyayı (os.O_CREAT | os.O_EXCL) seçenekleriyle
açmaya çalışıyor. Eğer o dosya daha önce oluşturulmuşsa, bir sonraki linkten
denemeye devam ediyor.
Peki, aşağıdaki şekilde yapmış olsak, işimizi görmez miydi?
Dürüst olmak gerekirse, eğer çok kritik bir iş yapmıyorsanız, bu yöntem de işinizi görebilir. Ancak, prensip olarak yanlış, çünkü, race-condition olarak tabir edilen duruma neden oluyor. Yani, yanyana çalışan işlemlerden birinin dosyanın olmadığını görmesi ile dosyayı oluşturması arasında geçen süre zarfında, diğer işlemler de aynı dosyanın olmadığını görüp oluşturmaya çalışacaklardır. Bu kimi zaman aynı dosyanın iki kere indirilmesine neden olacak, kimi zaman ise, beklenmedik hatalara yol açacaktır. Bu nedenle, (os.O_CREAT | os.O_EXCL) ile dosyanın olmaması halinde açılması tek adımda gerçekleştiği için, bu ihtimal ortadan kalkıyor. Bu şekilde dosya açmak, bir nevi mutex vazifesi görüyor.
Özetle, uygulamadaki basitliğinden ve esnekliğinden dolayı, uygun olduğu durumlarda, multiprocessing veya threading modüllerini kullanmak yerine, bu yöntemle yazdığım programı yanyana çalıştırıyorum. Şimdiye kadar herhangi bir sorunla karşılaşmadım. Siz de, basit uygulamalarınızda buradaki gibi bir yöntem kullanabilirsiniz.