Process, Thread ve Threadpool Kavramları
PROCESS
Bir program yazmak istediğimizde ilk yaptığımız, bir high level language kullanarak bu programın kodlarını yazmak olacaktır. Ancak, bilgisayarlar high level language’ı anlamaz sadece 0 ve 1lerden oluşan binary codeları anlarlar. Dolayısıyla yazdığımız programın binary code’a çevrilmesi gerekir. Bunun için de bir compiler yardımıyla programımızı compile ederiz. Bu da codeumuzu makinanın anlayabileceği machine koda çevirmemize yardımcı olur. Artık execution için hazır bir kodumuz vardır.
Ancak programı execute etmek için yalnızca binary codelara sahip olmak yeterli değildir. Aynı zamanda memorye yüklenmelidir ve programın execute edilmesi için, bilgisayar sisteminden kaynaklara ihtiyaç duyar. Bu kaynakları kim verecek? kim allocate edecek? Bunun arkasındaki beyin kimdir? Operating system. OS executable programın memory’e yüklenmesini sağlayacak ve resourceları allocate edecektir sonrasında da program execution’a başlayacaktır.
Önce, yazılmış ve execution için hazır bir programa sahibiz. Ancak bu noktada hala program pasif bir varlıktır. Yani hiç bir şey yapmadan durur. Ancak execution başladığı an bu programı process olarak adlandırılır. Yani process, execute edilmiş program olarak düşünülebilir. Execute edilmediği takdirde sadece boş duran bir programdır. Örneğin, bir yazılımcı olarak içerisine kodlar yazdığınız ve run ettiğiniz bir visual studionuz var. Bu bir processtir. Başka bir visual studio açıp bir program daha run ettiğinizde bu da bir başka processtir. Yani çalışan her program word, paint vs çalışmaya başladıkları an process olarak değerlendirilirler.
Eski bilgisayarlar tek seferde bir program çalıştırmayı desteklerdi. Ancak günümüz bilgisayarları aynı anda çalışan multiple process ve programları destekler. Hatta birden fazla process bir program ile ilişkilendirilebilir.
CONCURRENCY ve SINGLE CORE SISTEMLER
Concurrency denen durum aslında bir paralellik ilizyonu demektir. Yani birden fazla process concurrent olarak çalışıyorsa bunun anlamı aşağıdaki grafikteki gibi aslında bir zaman aralığında sadece bir processe ait işlemler ilerletilir ancak processler arası switch o kadar hızlıdır ki bize bir parallelik ilizyonu yaratır.
Gördüğünüz gibi tek çekirdekli(single core) bir sistemde herhangi bir zamanda yürütülen tek bir süreç vardır. Bu nedenle concurrency, gerçek paralel yürütmenin yalnızca genelleştirilmiş bir yaklaşımıdır. Tek çekirdekli işlemciye sahip sistemlerde bu tür durumlara rastlanabilmektedir. Pentium 4 tek çekirdekli işlemci döneminde, bilgisayar aynı anda sadece bir işlem veya iş parçacığını yürütürdü ve bu iş parçacıkları arasında hızlı bir şekilde geçiş yapardı. Bu da aynı anda gerçekleşiyormuş gibi bir izlenim yaratır; buna “Concurrency” denir. Tek çekirdekli işlemcilerde iş parçacıklarının gerçek anlamda paralel olaral yürütmesi mümkün değildir.
PARALLELISM veya MULTI CORE(Çok Çekirdekli) NEDIR?
Çok çekirdekli işlemcilerde paralel yürütme, bir süreç tarafından gerçekleştirilecek processler alt parçalara bölünür ve birden çok CPU (veya birden çok çekirdek) her bir alt görevi tam olarak aynı anda işler.
Gördüğünüz gibi herhangi bir zamanda tüm işlemler yürütülür. Gerçekte paralel olarak yürütülen,bir processin threadleridir ancak daha iyi anlamak için bunları processler olarak görselleştirebilirsiniz. Bu nedenle paralellik, birden fazla görevin aynı anda gerçekleştirilebilmesinin esas yoludur. Bu tür bir durum, hemen hemen tüm modern çok çekirdekli işlemcilere sahip sistemlerde bulunabilir.
THREAD
Thread process içindeki execution birimidir. Bir processin içerisinde bir ya da birden fazla thread olabilir. Yine eski sistemlerde bir process yalnızca bir threadi desteklerdi. Ancak günümüzde bir process çokça threadi destekleyebilir. Bir process birden fazla threadi destekliyorsa, aynı anda birden fazla task perform edebilir. Dolayısıyla threadler bir processin birden fazla iş yapmasını sağlayan yapılardır.
Multithreading ve Multitasking arasındaki fark ise multitasking birden fazla işlemin aynı anda işlenmesi, multithreading ise bir işlemdeki birden fazla iş parçacığının aynı anda işlenmesidir.
THREADPOOL
ThreadPool, bir dizi iş parçacığının oluşturulup yönetilmesi ve uygulama içinde çalışan thread sayısını daha aza indirgemek ve çalışan iş parçacıkları yönetmek için kullanılır. Bu sayede, uygulama birden çok görevi eşzamanlı olarak yürütebilir ve daha hızlı çalışabilir yani ThreadPool, arka planda belli bir işi yapmak üzere planlanmış görevlerin Thread’ lere bölünmesi ve bu Thread’ lerin bir koleksiyon şeklinde tutularak asenkron işleyişlerinin yönetilmesi amacıyla kullanılan bir tip olarak düşünülebilir Özellikle I/O yoğunluğu olan uygulamalarda (örneğin, dosya okuma/yazma veya ağ işlemleri gibi) ThreadPool’ün kullanılması, beklemeleri minimize eder ve uygulamanın daha hızlı yanıt vermesini sağlar.
ThreadPool, iş parçacıklarını yeniden kullanarak ve yöneterek, işlemci kaynaklarını verimli bir şekilde kullanmaya yardımcı olur. Bu da genellikle performansı artırır ve sistem kaynaklarından daha etkin bir şekilde yararlanılmasını sağlar.
Tabiki havuzunda belirli bir kapasitesi vardır. Bu kapasitenin dolu olması halinde ek olarak gelen görevler kuyrukta kalır ve ancak işleyen thread’ ler çalıştırılmaya müsait olduklarında icra edilebilir. Thread pool’un dolduğu durumda, yani mevcut iş parçacığı kaynakları tükenmişse, uygulama bu duruma genellikle iki şekilde tepki verebilir:
Bekleme (Waiting) : Eğer thread pool’da mevcut tüm iş parçacıkları başka görevlerle meşgul ise, yeni bir iş parçacığı oluşturulana kadar beklenir. Bu durumda, uygulama yeni iş parçacığı oluşturabilene kadar işlemi durdurur.
Hata Döndürme (Error Handling) : Eğer thread pool’da işlem yapacak iş parçacığı bulunmuyorsa ve yeni iş parçacığı oluşturulamıyorsa, bu durumda bir hata mesajı veya exception fırlatılabilir. Bu durumda, uygulama bu hatayı ele alarak uygun bir yanıt vermelidir. Bu yanıt, genellikle işlemin iptal edilmesi veya bekletilmesi gibi durumlar olabilir.
Hangi tepkinin verileceği, programlama diline ve kullanılan thread pool implementasyonuna göre değişebilir..
Threadpoolun iç yapısına bakarsak aslında yapılmak istenen işe ait havuza gelen her talep, havuz içerisinde bir thread’ e atanır ve asenkron olarak yürütülür. Burada ana uygulama thread’ ine bir bağımlılık söz konusu değildir. Hatta alt taleplerin bekletilmeside söz konusu değildir. Bununla birlikte önemli olan noktalardan biriside, işi biten bir görevin sahibi olan thread’ in tekrardan kullanılıncaya dek havuzda yer alan kuyruğa atılmasıdır.
Yönetim süreci genellikle bir kuyruk yapısıyla gerçekleştirilir; bu sayede çalışan işler sıralanabilir ve belirli zaman dilimlerinde çalışmaları planlanabilir. Örneğin, sunucu tarafında, kullanıcı isteklerine bağlı olarak yeni iş parçacıkları oluşturulur ve bu iş parçacıklarının tek görevi bu isteği yanıtlamaktır. Ancak burada bir dezavantaj ortaya çıkar: Her istek geldiğinde bir iş parçacığı oluşturmak için sunucu yoğun şekilde çalışır, iş parçacığı oluşturulduktan sonra isteği yanıtlamak için tekrar uğraşır ve bu süreçte önemli miktarda zaman ve kaynak harcar. Burada kuyrukta yer alan thread’ in, ana uygulama tarafından tekrardan kullanılması halinde, Thread oluşturma maliyetlerinin önüne geçilmesi mümkün hale gelmektedir ki bu bir avantajdır.
ThreadPool’ un temel olarak iki fonksiyonu olduğunu da düşünebiliriz. Bunlardan birincisi havuzda yer alan thread’ lerin üstlendiği işlerin tamamlanma durumlarını takip etmek, koordinasyonu sağlamak ve ikinci olarak da thread koleksiyonunu bir kuyruk düzeninde yönetmektir. Bir iş parçacığının yanıt verme süresini iyileştirmek için iş parçacıkları oluşturulabilir fakat bu iş parçacıklarını dikkatli şekilde oluşturmalıyız her yeni iş parçacı CPU’ya etkisi vardır.
THREAD SAFE
Thread Safe, Türkçe olarak iş parçacığı güvenliği olarak ifade edilebilecek bir kavramdır. Bu kavram, birden çok iş parçacığının aynı kaynağa aynı anda erişebileceği durumlarda oluşabilecek olası tutarsızlıkları ve hataları engellemek için o anki iş parçacığının kaynağı güvence altına alan bir konsepttir.
Yani şöyle düşünebiliriz: Eğer bir kaynağı bir thread okurken, aynı anda bir başka thread bu kaynağı değiştirirse, bu tür asenkron durumlarda hatalar oluşabilir. İşte bu tür hataları önlemek ve birden fazla thread’in kullandığı kaynak üzerindeki değişiklikleri sadece o anda değişiklik yapan thread’e aitmiş gibi göstermek için Thread Safe yöntemleri kullanılır yani Thread Safe genellikle bir veri yapısının doğru bir şekilde paylaşıldığından ve iş parçacıkları arasında doğru bir şekilde senkronize olduğundan emin olmak için kullanılır.
RACE CONDITION
Race condition terimi iki bağımsız eş sürecin (Process) aynı kaynak üzerine aynı zaman diliminde erişmeye çalışması sonucu bir sürecin diğerinden önce o kaynağa erişip farklı sonuçlar üretmesine yol açan durumu tanımlamaktadır yani Race Condition ise iş parçacıklarının paylaşılan bir kaynağa aynı anda erişmesi ve bu kaynağı aynı anda değiştirmeye çalışması durumunda ortaya çıkan bir hata türüdür de diyebiliriz.
Thread safe bir tasarım, birden fazla iş parçacığının aynı anda paylaşılan veriye erişse bile veri bütünlüğünü korur. Ancak, thread safe bir tasarım race condition’ı tamamen ortadan kaldırmaz; sadece olasılığını azaltır veya kontrol altına alır. Thread safe, thread safe bir class kullanıyorsanız programınızın race conditiondan arınmış olacağına dair bir garanti değildir. Yalnızca classın kendi kaynak kodunun programınızdaki threadleriyle ilgili hataların nedeni olmayacağını vaat ediyor.