karanlık proxyscrape logo

Eşzamanlılık vs Paralellik: Web Kazıma İçin Önemli Farklar

Kazıma, Farklılıklar, Ocak-01-20225 dakika okuma

When it comes to concurrency vs. parallelism, it may be apparent as they refer to the same concepts in executions of computer programs in a multi-threaded environment. Well, after looking at their definitions in the Oxford dictionary, you may be inclined to think so. However, when you go deeper into these notions with respect to

Eşzamanlılık ve paralellik söz konusu olduğunda, bilgisayar programlarının çok iş parçacıklı bir ortamda yürütülmesinde aynı kavramlara atıfta bulundukları anlaşılabilir. Oxford sözlüğündeki tanımlarına baktıktan sonra böyle düşünmeye meyilli olabilirsiniz. Ancak, CPU'nun program talimatlarını nasıl yürüttüğüne ilişkin bu kavramları daha derinlemesine incelediğinizde, eşzamanlılık ve paralelliğin iki farklı kavram olduğunu fark edeceksiniz. 

Bu makale, eşzamanlılık ve paralelliği, bunların nasıl değiştiğini ve program yürütme verimliliğini artırmak için birlikte nasıl çalıştıklarını daha derinlemesine incelemektedir. Son olarak, web kazıma için hangi iki stratejinin en uygun olduğu tartışılacaktır. Öyleyse başlayalım.

Eşzamanlı yürütme nedir?

İlk olarak, işleri daha basit hale getirmek için, tek bir işlemcide yürütülen tek bir uygulamadaki eşzamanlılıkla başlayacağız. Dictionary.com eşzamanlılığı birleşik eylem ya da çaba ve eşzamanlı olayların meydana gelmesi olarak tanımlar. Ancak, aynı şeyi paralel yürütme için de söyleyebiliriz, çünkü yürütmeler çakışır ve bu nedenle bu tanım bilgisayar programlama dünyasında biraz yanıltıcıdır.

Günlük yaşamda, bilgisayarınızda eşzamanlı yürütmeler olacaktır. Örneğin, Windows Media Player'ınızda müzik dinlerken tarayıcınızda bir blog makalesi okuyabilirsiniz. Başka bir web sayfasından PDF dosyası indirirken başka bir işlem çalışıyor olabilir; tüm bu örnekler ayrı işlemlerdir.

Eş zamanlı çalışan uygulamaların icadından önce, CPU'lar programları sırayla yürütüyordu. Bu, CPU bir sonrakine geçmeden önce bir programın talimatlarının yürütülmesinin tamamlanması gerektiği anlamına geliyordu.

Buna karşılık, eşzamanlı yürütme, hepsi tamamlanana kadar her işlemin bir kısmını değiştirir.

Tek işlemcili çok iş parçacıklı bir yürütme ortamında, bir program kullanıcı girişi için engellendiğinde diğeri yürütülür. Şimdi çoklu iş parçacığı ortamının ne olduğunu sorabilirsiniz. Birbirinden bağımsız olarak çalışan iş parçacıklarından oluşan bir koleksiyondur - bir sonraki bölümde iş parçacıkları hakkında daha fazla bilgi verilecektir.

Eşzamanlılık paralel yürütme ile karıştırılmamalıdır

Şimdi, eşzamanlılık ile paralelliği karıştırmak daha kolaydır. Yukarıdaki örneklerde eşzamanlılıkla kastettiğimiz şey, süreçlerin paralel olarak çalışmadığıdır. 

Bunun yerine, diyelim ki bir işlemin bir Giriş/Çıkış işleminin tamamlanmasını gerektirdiğini varsayalım, o zaman İşletim Sistemi CPU'yu başka bir işleme tahsis eder ve bu işlem I/O işlemini tamamlar. Bu prosedür tüm süreçler yürütmelerini tamamlayana kadar devam edecektir.

Ancak, görevlerin İşletim Sistemi tarafından değiştirilmesi bir nano veya mikrosaniye içinde gerçekleştiğinden, bir kullanıcıya süreçler paralel olarak yürütülüyormuş gibi görünecektir, 

İplik nedir?

Sıralı yürütmeden farklı olarak, CPU mevcut mimarilerde tüm süreci/programı bir kerede yürütmeyebilir. Bunun yerine, çoğu bilgisayar tüm süreci birbirinden bağımsız olarak keyfi bir sırayla çalışan birkaç hafif bileşene bölebilir. Bu hafif bileşenler iş parçacığı olarak adlandırılır.

Örneğin, Google Dokümanlar aynı anda çalışan birkaç iş parçacığına sahip olabilir. Bir iş parçacığı çalışmanızı otomatik olarak kaydederken, bir diğeri arka planda çalışarak yazım ve dilbilgisini kontrol edebilir.  

İşletim Sistemi sırayı ve hangi iş parçacıklarına öncelik verileceğini belirler, bu da sisteme bağlıdır.

Paralel yürütme nedir?

Artık bilgisayar programlarının tek bir CPU'nun bulunduğu bir ortamda yürütüldüğünü biliyorsunuz. Buna karşılık, modern bilgisayarlar paralel yürütme olarak bilinen birden fazla CPU'da birçok işlemi aynı anda yürütür. Mevcut mimarilerin çoğu birden fazla CPU'ya sahiptir.

Aşağıdaki diyagramda görebileceğiniz gibi, CPU bir sürece ait her bir iş parçacığını birbiriyle paralel olarak yürütür.  

Paralellikte, İşletim Sistemi iş parçacıklarını sistem mimarisine bağlı olarak makro veya mikrosaniyelik bölümler içinde CPU'ya geçirir ve CPU'dan geçirir. İşletim Sisteminin paralel yürütmeyi başarması için bilgisayar programcıları paralel programlama olarak bilinen kavramı kullanırlar. Paralel programlamada, programcılar birden fazla CPU'yu en iyi şekilde kullanmak için kod geliştirirler. 

Eşzamanlılık web kazımayı nasıl hızlandırabilir?

Web sitelerinden veri kazımak için web kazıma yöntemini kullanan bu kadar çok alan varken, büyük miktarlarda veriyi kazımak için harcanan zaman önemli bir dezavantajdır. Eğer deneyimli bir geliştirici değilseniz, kodu hatasız ve mükemmel bir şekilde çalıştırmadan önce belirli teknikleri denemek için çok fazla zaman harcayabilirsiniz.

Aşağıdaki bölüm, web kazıma işleminin yavaş olmasının bazı nedenlerini özetlemektedir.

Web kazımanın yavaş olmasının önemli nedenleri?

İlk olarak, kazıyıcı web kazıma işleminde hedef web sitesine gitmelidir. Ardından, kazımak istediğiniz HTML etiketlerinden varlıkları çekmesi ve alması gerekir. Son olarak, çoğu durumda, verileri CSV formatı gibi harici bir dosyaya kaydedersiniz.  

Gördüğünüz gibi, yukarıdaki görevlerin çoğu, web sitelerinden veri çekmek ve ardından bunları harici dosyalara kaydetmek gibi ağır bağlı I/O işlemi gerektirir. Hedef web sitelerine gitmek genellikle ağ hızı veya bir ağın kullanılabilir hale gelmesini beklemek gibi dış faktörlere bağlıdır.

Aşağıdaki şekilde de görebileceğiniz gibi, bu aşırı yavaş zaman tüketimi, üç veya daha fazla web sitesini kazımanız gerektiğinde kazıma işlemini daha da zorlaştırabilir. Kazıma işlemini sırayla gerçekleştirdiğiniz varsayılmaktadır.

Bu nedenle, öyle ya da böyle, kazıma işlemlerinize eşzamanlılık ya da paralellik uygulamanız gerekecektir. Paralelliği ilk olarak bir sonraki bölümde inceleyeceğiz.

Python kullanarak web kazımada eşzamanlılık

Şimdiye kadar eşzamanlılık ve paralellik hakkında genel bir bilgiye sahip olduğunuzdan eminim. Bu bölüm, Python'da basit bir kodlama örneği ile web kazımada eşzamanlılığa odaklanacaktır.

Eşzamanlı yürütme olmadan gösteren basit bir örnek

Bu örnekte, Wikipedia'dan nüfusa dayalı olarak başkentlerin bir listesine göre ülkelerin URL'sini kazıyacağız. Program bağlantıları kaydedecek ve ardından 240 sayfanın her birine gidecek ve bu sayfaların HTML'lerini yerel olarak kaydedecektir.

 Eşzamanlılığın etkilerini göstermek için iki program göstereceğiz - biri sıralı yürütme ve diğeri çoklu iş parçacıkları ile eşzamanlı olarak.

İşte kod:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import time

def get_countries():
    countries = 'https://en.wikipedia.org/wiki/List_of_national_capitals_by_population'
    all_countries = []
    response = requests.get(countries)
    soup = BeautifulSoup(response.text, "html.parser")
    countries_pl = soup.select('th .flagicon+ a')
    for link_pl in countries_pl:
        link = link_pl.get("href")
        link = urljoin(countries, link)
        
        all_countries.append(link)
    return all_countries
  
def fetch(link):
    res = requests.get(link)
    with open(link.split("/")[-1]+".html", "wb") as f:
        f.write(res.content)
  

        
def main():
    clinks = get_countries()
    print(f"Total pages: {len(clinks)}")
    start_time = time.time()
    for link in clinks:
        fetch(link)
 
    duration = time.time() - start_time
    print(f"Downloaded {len(links)} links in {duration} seconds")
main()

Kod açıklaması

İlk olarak, HTML verilerini çıkarmak için BeautifulSoap dahil olmak üzere kütüphaneleri içe aktarıyoruz. Diğer kütüphaneler arasında web sitesine erişmek için istek, keşfedeceğiniz gibi URL'lere katılmak için urllib ve programın toplam yürütme süresini bulmak için zaman kütüphanesi bulunur.

i̇thalat talepleri̇
from bs4 import BeautifulSoup
from urllib.parse import urljoin
İçe aktarma süresi

Program ilk olarak get_countries() fonksiyonunu çağıran ana modül ile başlar. Fonksiyon daha sonra HTML ayrıştırıcı aracılığıyla BeautifulSoup örneği üzerinden countries değişkeninde belirtilen Wikipedia URL'sine erişir.

Ardından, bağlantı etiketinin href niteliğindeki değeri çıkararak tablodaki ülkelerin listesi için URL'yi arar.

Aldığınız bağlantılar göreli bağlantılardır. urljoin fonksiyonu bunları mutlak bağlantılara dönüştürecektir. Bu bağlantılar daha sonra all_countries dizisine eklenir ve bu dizi ana fonksiyona geri döner 

Ardından fetch işlevi her bağlantıdaki HTML içeriğini bir HTML dosyası olarak kaydeder. Bu kod parçalarının yaptığı şey budur:

def fetch(link):
    res = requests.get(link)
    with open(link.split("/")[-1]+".html", "wb") as f:
        f.write(res.content)

Son olarak, ana fonksiyon dosyaları HTML formatında kaydetmek için geçen süreyi yazdırır. Bizim bilgisayarımızda 131,22 saniye sürdü.

Bu süre kesinlikle daha hızlı hale getirilebilir. Bunu, aynı programın birden fazla iş parçacığı ile yürütüldüğü bir sonraki bölümde öğreneceğiz.

Eşzamanlı aynı program

Çok iş parçacıklı sürümde, programın daha hızlı çalışması için küçük değişiklikler yapmamız gerekecektir.

Unutmayın, eşzamanlılık birden fazla iş parçacığı oluşturmak ve programı yürütmekle ilgilidir. İş parçacığı oluşturmanın iki yolu vardır - manuel olarak ve ThreadPoolExecutor sınıfını kullanarak. 

İş parçacıklarını manuel olarak oluşturduktan sonra, manuel yöntem için tüm iş parçacıklarında join işlevini kullanabilirsiniz. Bu şekilde, ana yöntem tüm iş parçacıklarının yürütülmesini tamamlamasını bekler.

Bu programda, concurrent. futures modülünün bir parçası olan ThreadPoolExecutor sınıfı ile kodu çalıştıracağız. Bu yüzden öncelikle yukarıdaki programa aşağıdaki satırı koymanız gerekiyor. 

from concurrent.futures import ThreadPoolExecutor

Bundan sonra, HTML içeriğini HTML biçiminde kaydeden for döngüsünü aşağıdaki gibi değiştirebilirsiniz:

  with ThreadPoolExecutor(max_workers=32) as executor:
           executor.map(fetch, clinks)

Yukarıdaki kod maksimum 32 iş parçacığı içeren bir iş parçacığı havuzu oluşturur. Her CPU için max_workers parametresi farklıdır ve farklı değerlerle denemeler yapmanız gerekir. İş parçacığı sayısı arttıkça yürütme süresinin daha hızlı olacağı anlamına gelmez.

Böylece bilgisayarımız 15,14 saniyelik bir çıktı üretti, bu da sırayla çalıştırdığımızdan çok daha iyi.

Bir sonraki bölüme geçmeden önce, işte eşzamanlı yürütme ile programın son kodu:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor
import time

def get_countries():
    countries = 'https://en.wikipedia.org/wiki/List_of_national_capitals_by_population'
    all_countries = []
    response = requests.get(countries)
    soup = BeautifulSoup(response.text, "html.parser")
    countries_pl = soup.select('th .flagicon+ a')
    for link_pl in countries_pl:
        link = link_pl.get("href")
        link = urljoin(countries, link)
        
        all_countries.append(link)
    return all_countries
  
def fetch(link):
    res = requests.get(link)
    with open(link.split("/")[-1]+".html", "wb") as f:
        f.write(res.content)


def main():
  clinks = get_countries()
  print(f"Total pages: {len(clinks)}")
  start_time = time.time()
  

  with ThreadPoolExecutor(max_workers=32) as executor:
           executor.map(fetch, clinks)
        
 
  duration = time.time()-start_time
  print(f"Downloaded {len(clinks)} links in {duration} seconds")
main()

Paralellik web kazımayı nasıl hızlandırabilir?

Artık eşzamanlı yürütme hakkında bir anlayış kazandığınızı umuyoruz. Daha iyi analiz etmenize yardımcı olmak için, aynı programın birden fazla CPU'da paralel olarak çalışan işlemlerle çok işlemcili bir ortamda nasıl performans gösterdiğine bakalım.

Öncelikle gerekli modülü içe aktarmanız gerekir:

from multiprocessing import Pool,cpu_count

Python, makinenizdeki CPU sayısını sayan cpu_count() yöntemini sağlar. Şüphesiz, paralel olarak gerçekleştirebileceği görevlerin kesin sayısını belirlemede yardımcı olur.

Şimdi sıralı yürütmede for döngüsü içeren kodu bu kodla değiştirmeniz gerekir:

ile Pool (cpu_count()) as p:
 
   p.map(fetch,clinks)

Bu kodu çalıştırdıktan sonra, ilk programdaki sıralı yürütmeden nispeten daha hızlı olan 20.10 saniyelik bir genel yürütme süresi üretti.

Sonuç

Bu noktada, paralel ve sıralı programlama hakkında kapsamlı bir genel bakışa sahip olabileceğinizi umuyoruz - birini diğerine tercih etmek öncelikle karşılaştığınız özel senaryoya bağlıdır.

Web kazıma senaryosu için, eşzamanlı yürütme ile başlamanın ve daha sonra paralel bir çözüme geçmenin harika olacağını öneriyoruz. Bu makaleyi okumaktan keyif aldığınızı umuyoruz. Blogumuzdaki bunun gibi web kazıma ile ilgili diğer makaleleri de okumayı unutmayın.