Skip to main content

Bir problemi hızlı çözmek istediğimizde thread ve processes’lere başvururuz.

Thread bilgisayar bilimleri alanında çok önemli bir konudur. Fakat bugün thread’in ve process’in ne olduğunu anlatıp, ardından bilgisayarımızın işlem gücünü sınayacağız.

Thread Nedir?

Thread, bilgisayarın bir process(işlem) içinde yürütülen bir birimdir. Modern bilgisayarlarda bir processte birden fazla thread yürütülebilmektedir. Bu sayede yapılacak olan işlerin hızlıca bitirilmesi olanak sağlanır. Ve az kaynak ile çok fazla işi bitirmiş olur.

Thread’ler, paralel işlem yapabilme yeteneği sayesinde çok fazla avantaj sağlamaktadır. Gelişen üretim teknolojileri ile çok çekirdekli işlemcilere erişim kolaylaştığından, geliştirdiğimiz yazılımlarda thread kullanmak faydalı olacaktır.

Thread kullanımı, avantajlarının yanı sıra bazı sorunları doğurmaktadır. Bunlar thread’lerin senkronizasyonu ve yönetimidir. Bu sorunları çözmek adına ileride bahsedeceğim bazı senkronizasyon algoritmaları ve mekanizmaları kullanılmaktadır.

Python’da thread yok!

Maalesef Python kullanarak thread oluşturamıyoruz. Eğer pythonda daha fazla işlem gücüne ihtiyacınız varsa malesef daha güçlü bir bilgisayara ihtiyacınız var demektir. Verimlilik açısından python gerçekten diğer rakiplerine göre (C++, Go, C#) dan geride kalmakta. Fakat bu, çok yavaş anlamına gelmiyor. Process kullanarak bir miktar daha hızlı yapılar oluşturabiliriz.

Process nedir diye bakacak olursak, bir programın yürütülmekte olan halidir. Yani işletim sistemine göre değişse de örnek bir processes’i şu şekilde anlayabilirsiniz.

Process, şekilde görünen görev yöneticisindeki Chrome alt işlemleridir. Burada chrome uygulamasın yanındaki 31 sayısından anlık olarak kaç adet process yürüttüğünü görebilirsiniz.

Thread ise az önce bahsettiğim gibi processes içindeki çoklu paralel çalışan yapıdır.

Elimizde taşınması gereken bir yük yığınımız olsun. Python’da alışık olduğumuz gibi sadece tek yönlü (yukardan aşağıya çalışan kod) bir çalışanımız var. Bu iş için ikinci bir çalışanı almak istediğimizde, bilgisayar bilimlerinde yeni bir kavram olan Paralel Programlama ortaya çıkıyor.

Şimdi Thread’i açıklamaya çalışayım. Sağ alta gösterdiğim Thread kutucuğunda 2 yuvarlak daire var Yani 2 adet process var. Fakat thread ise her bir yuvarlağın içindeki ipliklerdir. Bu iplikler semboliktir. Yani bir programın içinde paralel çalışan süreçlerin olduğunu belirtir. Processes ise uygulamalarımızın içindeki daha büyük paralel yapılardır.

Belki ilerleyen yazılarda C++ ile birlikte thread yazabiliriz. Şimdi neden Pythonda thread’in olmadığına bakalım.

Python’da Global Interpreter Lock (GIL) olarak bilinen bir mekanizma bulunur. Bu mekanizma, aynı anda birden fazla yerel Python kodunun yürütülmesini engeller. GIL, Python’un bellek yönetimini basitleştirir ve dilin performansını artırır çoklu iş parçacığı (threading) ile çalışmayı sınırlar.

GIL’den kaçınma yolu olarak “multiprocessing” modülünü kullanabiliriz. Fakat thread’ler oluşturulmaz. Bu modül ile Thread’ler(iş parçacıkları) yerine bağımsız processes(işlemler) oluşturur. Ve bu sayede birlikte paralel ilerleyen bir hesaplama yapabiliriz.

Multiprocessing ile ufak bir başlangıç

Birlikte 1’den 1000’e kadar tüm sayıların karesini alıp ekrana yazdıran kodu yazalım ve sonucuna bakalım. Önce multiprocessing kütüphanesini kullanarak 4 process ile işlemleri yaptıralım.

import multiprocessing

def square_number(number):
    return number * number

if __name__ == "__main__":
    # İşlem havuzu (pool) oluşturma
    with multiprocessing.Pool(processes=4) as pool:
        numbers = list(range(0,1000))
        results = pool.map(square_number, numbers)

    print(results)

multiprocessing kütüphanesinin Pool sınıfı ile bir havuz oluşturduk. Ve processes metodunu kullanarak 4 işlem çalıştırmak istedik.

Görüldüğü gibi kod bize tüm sayıların karelerini alıp verdi.

Şimdi kodumuza ufak bir benchmark ekleyelim. Ve şu şekilde kaç saniyede yaptığına bakalım.

import multiprocessing
import time

def square_number(number):
    return number * number

if __name__ == "__main__":
    # İşlem havuzu (pool) oluşturma
    start = time.time()
    with multiprocessing.Pool(processes=4) as pool:
        numbers = list(range(0,1000))
        results = pool.map(square_number, numbers)
    end = time.time()
    print("Parallel\n", end-start)

Görüldüğü üzere 0.10 saniyede yaptık işlemimizi, processes kullanmasaydık ne olurdu birde ona bakalım.

import time

def square_number(number):
    return number * number

if __name__ == "__main__":
    # Non parallel
    start = time.time()
    results = []
    numbers = list(range(0,1000))
    for number in numbers:
        results.append(square_number(number))
    end = time.time()
    print("Non Parallel\n", end-start)

Bu kod normal şekilde problemi çözmek için normalde yaklaştığımız şekildedir. Kodu çalıştırdığımızda

Görüldüğü üzere o kadar kısa sürede hesapladı ki, hızlanmak isterken daha yavaşlamış olduk. Yani normalden daha yavaş olduğunu görüyoruz. Çünkü yeterince büyük bir veriye sahip değiliz. Ve bu case te normalden daha hızlı bir sonuç beklerken processes kullanıldığındaki zaman maliyetinden dolayı daha yavaş bir sonuç alıyoruz. Şuan 0 saniye yazması işlemcimizin çok küçük bir sürede hesap yapmasından ve bu farkın ondalık biçimden küçük gözükmesi yüzünden olmaktadır. Biz nerede göreceğiz paralel çalışmanın farkını diyecek olursak daha büyük verilerde anlaşılabilir.

Büyüyen Veri ve Verimli Hesaplama

Şuan 2 milyona kadar tüm sayıların karesini paralel olarak alıyoruz. Ve kaç saniye sürdüğüne bakalım.

Görüldüğü gibi 2.57 saniye sürdü. Hızlı değil mi? şimdi process olmadan hesaplayalım.

Görüldüğü üzere 2.87 saniyede tek bir process ile hesaplamayı bitirdi. multiprocessing ile büyük verilerde her ne kadar maliyetli olsa da çoklu işlem yaparak zamandan tasarruf sağlayabildik.

Sona doğru

Belki de yazı şu an için kısa olabilir, fakat verilerin hesaplanmasında multiprocessing kullanımına dair sizlere fikir vermesi adına iyi bir başlangıç olacağını düşünüyorum.

Verilerin büyüdüğü işlem adımların fazlalaştığında multiprocessing bir nebze sizlere yardımı dokunabilir. Ama veriniz küçük olduğunda maalesef yeni bir process açılması, hesaplanması ve kapatılmasının bize bir zaman ve kaynak maliyeti oluyor. Burada duruma göre karar vermek programcıya kalmış oluyor.

Bu konu ile alakalı bir seriye başlıyorum. Yorumlarda desteğinizi görmek isterim. Ayrıca eklenmesini istediğiniz konuyu yorumlarda belirtirseniz düzenlemeye çalışır, birlikte çözebiliriz.

Fotoğraf: Anni Roenkae: https://www.pexels.com/tr-tr/fotograf/yakin-cekim-fotograf-resmi-3219948/

Leave a Reply