0Pricing
C Academy · Ders

Bloklayan ve Bloklamayan G/Ç

Olay döngülerinin neden önemli olduğunu öğrenin.

Bloklayan ve Bloklamayan G/Ç, CoddyKit'te ücretsiz bir C Academy dersidir. Bu, 4 dersinin 1. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, C Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. C Academy kursu toplamda 4 dersten oluşur.

Engellemenin Anlamı

Engelleyici bir sistem çağrısı, işlem ilerleyebilene kadar çağrıyı yapan iş parçacığını askıya alır. Verisi olmayan bir sokette recv() çağırdığınızda çekirdek, baytlar gelene kadar iş parçacığınızı bekletir.

Bunun akıl yürütmesi basittir: tek bağlantı, tek iş parçacığı ve doğrusal kod. Binlerce istemciye aynı anda hizmet vermeniz gerektiğinde maliyet ortaya çıkar.

ssize_t n = recv(fd, buf, sizeof buf, 0);
/* thread sleeps here until data or error */
if (n > 0) handle(buf, n);

Ölçekleme Sorunu

Engelleyici G/Ç ile takılan bir istemci tüm iş parçacığını engeller. Klasik çözüm, her bağlantı için bir iş parçacığı (veya süreç) oluşturmaktır.

Bu bir noktaya kadar işe yarar; ancak 10.000 iş parçacığı, 10.000 yığın, yoğun bağlam değiştirme ve zamanlayıcı ek yükü demektir. Sunucuları olay güdümlü tasarımlara yönelten ünlü C10k sorunu budur.

Engelleyici Olmayan Kip

Engelleyici olmayan bir soket hiçbir zaman beklemez. Bir çağrı hemen tamamlanamazsa derhâl -1 döndürür ve errno değerini EAGAIN veya EWOULDBLOCK olarak ayarlar.

Artık daha sonra yeniden denemek kodunuzun sorumluluğundadır. Bu, tek bir iş parçacığının hiçbir sokette takılmadan birçok soketi yönetmesini sağlar.

ssize_t n = recv(fd, buf, sizeof buf, 0);
if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
    /* no data right now, try again later */
}

fcntl ile O_NONBLOCK Ayarlama

Bir tanımlayıcıyı fcntl() ile O_NONBLOCK bayrağını ekleyerek engelleyici olmayan duruma geçirirsiniz. Önce her zaman geçerli bayrakları okuyun, ardından diğer ayarları ezmemek için bite OR uygulayın.

Aynı yardımcı, dinleme soketlerinde, kabul edilen istemci soketlerinde ve boru hatlarında da kullanılır.

int set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) return -1;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

Kısmi Okumaları Ele Alma

Engelleyici olmayan G/Ç, kısmi işlemleri olağan hâle getirir. Bir recv() istenenden daha az bayt döndürebilir ve send() arabelleğinizin yalnızca bir bölümünü kabul edebilir.

Ne kadar gönderdiğinizi veya aldığınızı izlemeli ve oradan devam etmelisiniz. Tek bir çağrının tüm baytları taşıdığını asla varsaymayın.

size_t sent = 0;
while (sent < len) {
    ssize_t w = send(fd, buf + sent, len - sent, 0);
    if (w < 0) { if (errno == EAGAIN) break; else return -1; }
    sent += w;
}

Meşgul Bekleme Yanlıştır

Engelleyici olmayan soketleri kullanmanın saf yolu, hepsi üzerinde döngüye girip sürekli yeniden denemektir. Bu meşgul bekleme, hiçbir şey olmuyorken bile CPU'nun %100'ünü tüketir.

Aslında çekirdeğe şunu sormak isteriz: "Hangi tanımlayıcıların hazır olduğunu söyle ve o zamana kadar uyumama izin ver." Hazır olma bildirimi tam olarak bunu sağlar.

Hazır Olma Bildirimi

G/Ç çoklama, tek bir iş parçacığının birçok tanımlayıcıyı aynı anda beklemesini ve yalnızca en az biri hazır olduğunda uyanmasını sağlar. İzlemeyi sizin yerinize çekirdek yapar.

Klasik arayüzler select() ve poll()'dur. İşe yararlar; ancak her çağrıda her tanımlayıcıyı yeniden taradıkları için ölçek büyüdüğünde pahalı hâle gelirler.

fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
select(fd + 1, &rfds, NULL, NULL, NULL);

select ve poll Neden Ölçeklenemez

Hem select() hem de poll() O(n)'dir: her çağrı tüm tanımlayıcı kümesini çekirdeğe gönderir; çekirdek bunların hepsini tarar, ardından hazır olanları bulmak için siz de hepsini yeniden tararsınız.

select() ayrıca yaklaşık FD_SETSIZE değerinde (çoğunlukla 1024) sınıra ulaşır. Binlerce bağlantıda bu ek yük baskın hâle gelir.

epoll ile Tanışma

epoll, Linux'un ölçeklenebilir çözümüdür. Bir tanımlayıcıya yönelik ilgiyi bir kez kaydedersiniz ve çekirdek hazır olma durumunu izleyen dahili bir veri yapısını korur.

Her bekleme yalnızca gerçekten hazır olan tanımlayıcıları döndürür; bu nedenle maliyet toplam bağlantı sayısına değil, etkin bağlantı sayısına göre ölçeklenir. Böylece hazır her olay için yaklaşık O(1) maliyet elde edilir.

int epfd = epoll_create1(0);
/* register fds once, then wait for ready events */

Engelleyici Olmayan Soketler ve epoll

epoll ile engelleyici olmayan soketler birlikte çalışır. epoll size bir tanımlayıcının hazır olduğunu söyler; engelleyici olmayan çağrılar ise hiçbir zaman beklemeden tanımlayıcıdaki veriyi tüketmenizi sağlar.

epoll'e vereceğiniz soketlerde her zaman O_NONBLOCK ayarlamalısınız. Aksi hâlde sahte bir uyanma veya kısmi bir okuma, tek olay döngüsü iş parçacığınızı engelleyebilir.

set_nonblocking(conn_fd);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = conn_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, &ev);

Zihinsel Model

Sunucuyu bir döngü olarak düşünün: epoll_wait() içinde bekleyin, hazır tanımlayıcılardan oluşan küçük bir liste alın, her biri üzerinde engelleyici olmayan işlemler yapın ve tekrarlayın.

İş yokken iş parçacığı uyur, yalnızca gerçek iş için uyanır. Artık tek bir iş parçacığı on binlerce bağlantıya verimli biçimde hizmet verebilir.

Hızlı Kontrol

Engelleyici olmayan soketleri anlayıp anlamadığınızı sınayın.

Özet

Engelleyici G/Ç basittir; ancak her bağlantı için bir iş parçacığını meşgul eder ve bu, ölçek büyüdüğünde başarısız olur. Engelleyici olmayan G/Ç, uyumak yerine EAGAIN ile hemen döner.

Soketleri sıkı bir döngüde yoklamak CPU'yu boşa harcar; bu nedenle hazır olma bildirimini kullanırız. select/poll O(n)'dir; epoll ise binlerce bağlantıya ölçeklenir. Sırada epoll'ü kurmak var.

Sıkça Sorulan Sorular

“Bloklayan ve Bloklamayan G/Ç” dersi ücretsiz mi?

Evet — “Bloklayan ve Bloklamayan G/Ç” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve C Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. C Academy kursu toplamda 4 dersten oluşur.

“Bloklayan ve Bloklamayan G/Ç” dersinde ne öğreneceğim?

Olay döngülerinin neden önemli olduğunu öğrenin. C Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

C Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te C Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 1. dersidir.

“Bloklayan ve Bloklamayan G/Ç” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu C Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her C Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Bloklayan ve Bloklamayan G/Ç
  2. epoll Kurulumu
  3. Olay Döngüsü
  4. Basit Bir Yankı Sunucusu
← C Academy Sayfasına Dön