PYTHON İLE ASENKRON I/O İŞLEMLERİ

Elif İ. Eser
Nettsi Bilişim Teknoloji A.Ş.
3 min readJan 29, 2021

Bu yazımı konsoldan çalışan bir uygulamanın Black Box testlerini yaparken karşılaştığım bir problem üzerine kaleme alıyorum. Konsol uygulaması çalıştırıldıktan sonra bir takım işlemler yapmakta ve sonrasında ürettiği sonucu bir dosyaya yazmaktaydı. Python test script’i ile test edeceğim harici uygulamayı çalıştırdığımda uygulama tarafından dosyaya yazma işleminin ne zaman tamamlanacağını bilemediğim için test işlemini sağlıklı olarak gerçekleştiremedim. Python script’i içerisinde, harici uygulamanın dosyaya yazma işlemini tamamlamasını beklemek için, önceleri sleep komutunu kullanmak zorunda kaldım. Bu yöntemin kullanışsız olmasından dolayı problemi nasıl çözebileceğimi araştırdığımda çözüm olarak Python ile asenkron Giriş/Çıkış (I/O) işlemini buldum. Uygulama tarafından dosyaya yazma işlemi Python script’inden bağımsız yani asenkron olarak gerçekleştiğinden dolayı dosya üzerinde yapılan işlemleri bir şekilde izlemek gerekiyordu. Şimdi yazıma kısaca asenkron I/O işlemi nedir diyerek başlamak istiyorum.

Asenkron I/O işlemleri Nedir?

Senkron ve asenkron olmak üzere iki tür I/O işlemi bulunmaktadır. Senkron I/O işlemlerinde uygulama bloklanmakta yani I/O işlemi tamamlanana kadar beklenilmektedir. Asenkron I/O işlemlerinde ise olayın tamamlanması beklenmez, uygulama bloklanmaksızın bu süreç boyunca başka işlemler yapılabilir. I/O olayı tamamlandığında çoğunlukla bir callback fonksiyonu üzerinden haberdar olunup gerekli işlemlerin yapıldığı I/O modelidir.

Şimdi size Python ile asenkron I/O modelini kullanarak dosya izlemeyi anlatacağım.

Öncelikle asenkron I/O işlemi için iki modül gerekmektedir. Fcntl ve signal modülleri burada kullanacağımız iki önemli modüldür. Kısaca bu modüllerden bahsettikten sonra kod üzerinden açıklama yapacağım. Öncelikle aşağıdaki gibi modüllerimizi çalıştığımız dosyaya import ediyoruz.

Kısaca yukarıdaki modüllerden bahsedelim.

Fnctl Modülü: Bu modül dosya kontrolü ve dosya tanımlayıcıları üzerinde I/O kontrolü sağlar. Detaylı bilgi için python döküman sayfasına bakabilirsiniz.

Signal Modülü: Bu modül Python’da sinyaller ile çalışmak için gerekli mekanizmayı sağlar. Sinyaller bir programa bir olayı bildiren ve olayın asenkron olarak işlemesini saylayan işletim sistemi özelliğidir. Detaylı bilgi için python dökümanına bakabilirsiniz.

Os Modülü: Farklı işletim sistemleri ile tutarlı bir şekilde iletişim kurabilmemizi sağlayacak pek çok fonksiyon sunan bir modüldür.

Şimdi yavaş yavaş kodumuzun içine doğru girelim.

Öncelikle bu yazılan script, komut satırında çalıştırılacak uygulamanın üreteceği dosya üzerinde işlem yapmayı hedeflemektedir. Burada açıklayacaklarım kodun sadece asenkron I/O ile ilgili olan kısımları olacaktır.

Aşağıdaki kodda workspace değişkeni ile çalıştığımız dizini belirliyoruz. Dizini bulmak için os modülü kullanıyoruz. Komut çalıştırıldıktan sonra dosyaya yazdırma işleminin yapılacağı dizini değişken olarak tanımlıyoruz, eğer ilgili dizin yoksa bu dizini oluşturuyoruz (ben dizine asnc adını verdim siz istediğiniz gibi oluşturabilirsiniz.). Son olarak fname olarak tanımladığımız kısım dosyamızın bulunduğu dizinin full path’idir.

workspace = os.getcwd() 
directory = "asnc"
if not os.path.exists(directory):
directory=os.mkdir("asnc")
working_dirname = f"{workspace}/{directory}"
fname = f"{working_dirname}/{file_name}"

previous değişkeni ile “fname” ismi ile verilen dosyanın en son ne zaman modifiye edildiğini öğreniyoruz.

Burada handler isimli fonksiyon sinyal gönderildiğinde çağrılacak callback fonksiyonudur. signum sinyal numarası, frame sinyal tarafından kesintiye uğrayan fonksiyona ilişkin yığın (stack) alanını temsil etmektedir. Sinyal tespit edildiğinde bu fonksiyon çalıştırılır.

signal.signal(signal.SIGIO, handler)

Signal.signal() fonksiyonu sinyal alındığında yürütülecek olan özel işlemlerinin tanımlanmasına izin verir. Örnek vermek gerekirse bir uygulamanın “Ctrl+c” (SIGINT) sinyali aldığı her seferde tanımladığı bir handler var ise onu işleyeceği gibi…

fd = os.open(working_dirname, os.O_RDONLY)

fd (file descriptor) dosya tanımlayıcısıdır. Dosya numarasını almak için kullanılır. os.open fonksiyonu kullanarak işlem yapacağımız dosya için dosya tanımlayıcı elde ediyoruz.

Fcntl modülü dosya tanımlayıcıları üzerinde dosya ve I/O kontrolü gerçekleştirir. İşlem yapmak istediğimiz dosyanın dosya tanımlayıcısını elde etmiştik sonrasında bu değer fnctl fonksiyonuna geçirilmelidir. fnctl fonksiyonuna ayrıca yukarıdaki örnekte gösterildiği gibi uygun fcntl.F_SETSIG ve fcntl.F_NOTIFY değerleri geçirilmelidir. F_NOTIFY için geçirilen değerler ve anlamları aşağıdadır.

DN_ACCESS: Dosyaya erişildi.

DN_MODIFY: Dosya düzenlendi.

DN_CREATE: Dosya oluşturuldu.

DN_DELETE: Dosya silindi.

DN_RENAME: Dosyanın ismi değiştirildi.

DN_ATTRIB: Dosyanın özellikleri değiştirildi.

Genellikle dosya bildirimleri Oneshot’tur (tek seferliktir). Başvurulan yeni değerlerin alınabilmesi için kayıt yaptırılması gerekmektedir. Burada DN_MULTISHOT dahil edildiği için bildirim açıkça kaldırılana kadar işlem yürürlükte kalacaktır.

Sonuç Olarak;

Dosyada meydana gelen değişiklikleri çalışan uygulamamızın sonlanmasını beklemeden asenkron I/O işlemleri ile izlemiş olduk.

Python kodunun tamamı aşağıdaki gibidir.

Not: Dosya tanımlayıcısını tanımlarken os.open içerisine argüman olarak izlemek istediğimiz dosyaya ait klasör ismini vermemiz gerekiyor yoksa Python bu komutu çalıştırırken hata veriyor ve sinyal ile dosya izleme işlemini gerçekleştiremiyor.

Umarım faydalı bir yazı olmuştur. Bir sonraki yazımda görüşmek üzere….

REFERANSLAR:

--

--

Elif İ. Eser
Nettsi Bilişim Teknoloji A.Ş.

"Knowledge should not be confined within the walls of academia."