Node.js, dahili olarak Threads'e güveniyorsa doğal olarak nasıl daha hızlıdır?


281

Ben sadece şu videoyu izledim: Node.js'ye giriş ve hala hız avantajlarını nasıl elde ettiğinizi anlamıyorum.

Temelde, bir noktada Ryan Dahl (Node.js'nin yaratıcısı), Node.js'nin iş parçacığı tabanlı yerine olay döngüsü tabanlı olduğunu söylüyor. İş parçacıkları pahalıdır ve yalnızca kullanılacak eşzamanlı programlama uzmanlarına bırakılmalıdır.

Daha sonra, kendi İş Parçacığı havuzunu dahili olarak barındıran bir C uygulaması olan Node.js'nin mimari yığınını gösterir. Açıkçası Node.js geliştiricileri asla kendi iş parçacıklarını başlatmazlar veya doğrudan iş parçacığı havuzunu kullanmazlar ... zaman uyumsuz geri çağrılar kullanırlar. Anladığım kadarıyla.

Ne anlamadım Node.js hala iş parçacığı kullanıyor nokta ... sadece uygulama gizleme bu yüzden 50 kişi 50 dosya (şu anda bellekte değil) iyi talep sonra 50 iş parçacığı gerekli değilse bu nasıl daha hızlı ?

Tek fark, dahili olarak yönetildiği için Node.js geliştiricisinin iş parçacığı ayrıntılarını kodlaması gerekmiyor, ancak bunun altında hala IO (engelleme) dosya isteklerini işlemek için iş parçacıklarını kullanıyor olması.

Yani gerçekten sadece bir problem alıp (iş parçacığı) ve bu problem hala devam ederken saklanmıyor musunuz: esas olarak çoklu iş parçacıkları, bağlam değiştirme, ölü kilitler ... vb?

Burada hala anlamadığım bazı detaylar olmalı.


14
Talebin biraz fazla basitleştirilmiş olduğu konusunda sizinle aynı fikirdeyim. Düğümün performans avantajının iki şeye düştüğüne inanıyorum: 1) gerçek iş parçacıklarının tümü oldukça düşük bir seviyede bulunur ve bu nedenle boyut ve sayı bakımından kısıtlı kalır ve iş parçacığı senkronizasyonu böylece basitleştirilir; 2) İşletim sistemi düzeyinde "geçiş" select(), iş parçacığı içeriği değişimlerinden daha hızlıdır.
Sivri

Yanıtlar:


140

Aslında burada birbirinden farklı birkaç şey var. Ancak, iş parçacığı gerçekten zor olduğu meme ile başlar. Eğer zorlarsa, 1) hatalar nedeniyle kopma ve 2) bunları mümkün olduğunca verimli kullanmama olasılığınız daha yüksektir. (2) sormak istediğiniz kişidir.

Verdiği örneklerden birini, bir isteğin geldiğini ve bazı sorgu çalıştırdığınızı düşünün ve ardından bunun sonuçlarıyla bir şeyler yapın. Standart bir yordamsal yöntemle yazarsanız, kod şöyle görünebilir:

result = query( "select smurfs from some_mushroom" );
// twiddle fingers
go_do_something_with_result( result );

Gelen istek, yukarıdaki kodu çalıştıran yeni bir iş parçacığı oluşturmanıza neden olduysa, orada çalışırken bir iş parçacığına sahip olursunuz query(), çalışırken hiçbir şey yapmazsınız. (Ryan'a göre Apache, orijinal talebi karşılamak için tek bir iş parçacığı kullanıyor, oysa nginx söz konusu olduğu durumlarda söz konusu olduğu durumlarda daha iyi performans gösteriyor.)

Şimdi, gerçekten akıllı olsaydınız, yukarıdaki kodu, sorguyu çalıştırırken ortamın gidebileceği ve başka bir şey yapabileceği bir şekilde ifade edersiniz:

query( statement: "select smurfs from some_mushroom", callback: go_do_something_with_result() );

Bu temelde node.js'nin yaptığı şeydir. Temel olarak, dil ve çevre, dolayısıyla kapanışlarla ilgili noktalar nedeniyle uygun bir şekilde - kodunuzu, ortamın neyin ne zaman ve ne zaman çalıştığı konusunda akıllı olabileceği şekilde dekore ediyorsunuz. Bu şekilde, node.js, eşzamansız G / Ç'yi icat ettiği anlamında yeni değildir (böyle bir şey iddia eden kişi değildir), ancak ifade edilme şekli biraz farklıdır.

Not: Ortamın neyin ve ne zaman çalıştığı konusunda akıllı olabileceğini söylediğimde, özellikle kastettiğim, bazı G / Ç'yi başlatmak için kullanılan iş parçacığının artık başka bir isteği veya yapılabilecek bazı hesaplamaları işlemek için kullanılabileceği veya başka bir paralel I / O başlatın. (Aynı düğüm için daha fazla iş başlatmak için yeterince düğümlü olmadığından emin değilim, ama fikri anladınız.)


6
Tamam, bunun performansı nasıl artırabildiğini kesinlikle görebiliyorum çünkü CPU'nuzu en üst düzeye çıkarabiliyorsunuz gibi geliyor, çünkü Ryan'ın yaptığı şeyin etkili bir şekilde bulunması için IO'nun geri dönmesini bekleyen herhangi bir iş parçacığı veya yürütme yığını yok tüm boşlukları kapatmanın bir yolu.
Ralph Caraveo

34
Evet, söyleyeceğim tek şey, boşlukları kapatmanın bir yolunu bulması değil: yeni bir model değil. Farklı olan, programcının programlarını bu tür bir eşzamansızlık için çok daha uygun bir şekilde ifade etmesine izin vermek için Javascript kullanmasıdır. Muhtemelen bir nitpicky detay, ama yine de ...
jrtipton

16
Ayrıca, G / Ç görevlerinin birçoğu için, Node'un çekirdek düzeyinde async G / Ç api (epoll, kqueue, / dev / anket, ne olursa olsun) kullandığını belirtmek gerekir
Paul

7
Hala tam olarak anladığımdan emin değilim. Bir web isteği içinde G / Ç işlemlerinin, isteği işlemek için çoğu zaman alan işlemler olduğunu düşünürsek ve her G / Ç işlemi için yeni bir iş parçacığı oluşturulursa, çok hızlı bir şekilde gelen 50 istek için, muhtemelen paralel olarak çalışan ve IO bölümünü yürüten 50 iş parçacığı vardır. Standart web sunucularından farkı, orada tüm isteğin iş parçacığında yürütülmesi, node.js'de ise yalnızca IO kısmıdır, ancak bu çoğu zaman alan ve iş parçacığını bekleten kısımdır.
Florin Dumitrescu

13
@SystemParadox Bunu belirttiğin için teşekkürler. Aslında son zamanlarda konuyla ilgili biraz araştırma yaptım ve asıl önemli olan async I / O'nun çekirdek düzeyinde düzgün bir şekilde uygulandığında async I / O işlemleri yaparken iş parçacığı kullanmamasıdır. Bunun yerine, G / Ç işlemi başlatılır çağrılmaz iş parçacığı serbest bırakılır ve G / Ç işlemi tamamlandığında ve iş parçacığı kullanılabilir olduğunda bir geri arama yürütülür. Bu nedenle node.js, G / Ç işlemleri için eşzamansız destek düzgün bir şekilde uygulanırsa, (neredeyse) paralelde 50 G / Ç işlemi ile 50 eşzamanlı istek çalıştırabilir.
Florin Dumitrescu

32

Not! Bu eski bir cevap. Zorlu taslakta hala doğru olsa da, Node'un son birkaç yıldaki hızlı gelişimi nedeniyle bazı detaylar değişmiş olabilir.

Konu kullanıyor çünkü:

  1. Açık O_NONBLOCK seçeneği () dosyalar üzerinde çalışmaz .
  2. Engellemeyen G / Ç sunmayan üçüncü taraf kütüphaneler vardır.

Tıkanmasız IO'yu taklit etmek için, dişliler gereklidir: IO'yu ayrı bir iş parçacığında engelleme. Çirkin bir çözümdür ve çok fazla ek yüke neden olur.

Donanım düzeyinde daha da kötü:

  • İle DMA CPU uyumsuz IO boşaltır.
  • Veriler doğrudan IO cihazı ile bellek arasında aktarılır.
  • Çekirdek bunu senkron, engelleme sistemi çağrısında sarar.
  • Node.js engelleme sistemi çağrısını bir iş parçacığına sarar.

Bu sadece aptalca ve verimsiz. Ama en azından işe yarıyor! Node.js'nin tadını çıkarabiliriz, çünkü olay odaklı asenkron bir mimarinin arkasındaki çirkin ve hantal ayrıntıları gizler.

Belki birisi gelecekte dosyalar için O_NONBLOCK uygular? ...

Düzenleme: Bir arkadaşla tartıştık ve o parçacığı alternatif ile yoklama olduğunu söyledi seçme : (bunlar bloğuna garanti olduğunu şimdi) 0 bir zaman aşımı belirtmek ve döndürülen dosya göstericisi üzerinde IO yok.


Peki ya Windows?
Pacerier

Üzgünüm, hiçbir fikrim yok. Sadece libuv'un eşzamansız iş yapmak için platformdan bağımsız bir katman olduğunu biliyorum. Düğümün başlangıcında libuv yoktu. Daha sonra libuv'u bölmeye karar verildi ve bu platforma özgü kodu daha kolay hale getirdi. Başka bir deyişle, Windows'un Linux'tan tamamen farklı olabilecek kendi asenkron hikayesi var, ama bizim için önemli değil çünkü libuv bizim için zor işi yapıyor.
nalply

28

Korkarım burada "yanlış bir şey yapıyorum", eğer öyleyse beni sil ve özür dilerim. Özellikle, bazı insanların yarattığı düzgün küçük ek açıklamaları nasıl oluşturduğumu göremiyorum. Ancak, bu iş parçacığı üzerinde yapmak için birçok endişe / gözlem var.

1) Popüler cevaplardan birinde sahte kodda yorumlanan öğe

result = query( "select smurfs from some_mushroom" );
// twiddle fingers
go_do_something_with_result( result );

aslında sahte. İş parçacığı hesaplanıyorsa, baş döndürücü değil, gerekli işi yapıyor. Öte yandan, sadece IO tamamlanması bekliyor, o zaman oluyor değil CPU zamanı kullanarak çekirdekteki iplik kontrol altyapısının bütün mesele işlemci yapmak için yararlı bir şeyler bulacaksınız olmasıdır. Burada önerildiği gibi "başparmaklarınızı çevirmek" için tek yol bir yoklama döngüsü oluşturmak olacaktır ve gerçek bir web sunucusu kodlayan kimse bunu yapmak için yeterince beceriksiz.

2) "İş parçacıkları zor", yalnızca veri paylaşımı bağlamında anlamlıdır. Bağımsız web isteklerini işlerken olduğu gibi temel olarak bağımsız iş parçacıklarınız varsa, iş parçacığı basit bir şekilde basittir, sadece bir işin nasıl işleneceğinin doğrusal akışını kodlarsınız ve çok sayıda isteği işleyeceğini bilerek oturursunuz. etkin bir şekilde bağımsız olacak. Şahsen, çoğu programcı için, kapatma / geri arama mekanizmasını öğrenmenin sadece yukarıdan aşağıya iplik versiyonunu kodlamaktan daha karmaşık olduğunu düşünürüm. (Ama evet, eğer iş parçacıkları arasında iletişim kurmak zorunda kalırsanız, hayat gerçekten hızlı bir şekilde zorlaşır, ama sonra kapatma / geri arama mekanizmasının gerçekten bunu değiştirdiğinden emin değilim, sadece seçeneklerinizi kısıtlar, çünkü bu yaklaşım hala iş parçacıkları ile gerçekleştirilebilir Her neyse, bu '

3) Şimdiye kadar, hiç kimse belirli bir bağlam anahtarının neden diğer türlerden daha fazla veya daha az zaman alacağına dair gerçek bir kanıt sunmamıştır. Çok görevli çekirdek oluşturma deneyimim (katıştırılmış denetleyiciler için küçük bir ölçekte, "gerçek" bir işletim sistemi kadar süslü bir şey yok) bu durumun böyle olmayacağını gösteriyor.

4) Düğümün diğer web sunucularından ne kadar daha hızlı olduğunu iddia ettiğine dair gördüğüm tüm illüstrasyonlar korkunç bir şekilde kusurludur, ancak Düğüm için kesinlikle kabul edeceğim bir avantajı dolaylı olarak gösteren bir şekilde kusurludur (ve hiçbir şekilde önemsiz değildir). Düğüm ayarlamaya ihtiyaç duymuyor (hatta izin veriyor). Dişli bir modeliniz varsa, beklenen yükü kaldıracak yeterli dişler oluşturmanız gerekir. Bunu kötü bir şekilde yapın, sonuçta düşük performans elde edersiniz. Çok az sayıda iş parçacığı varsa, CPU boştadır, ancak daha fazla istek kabul edemez, çok fazla iş parçacığı oluşturur ve çekirdek belleğini boşa harcarsınız ve Java ortamı durumunda, ana yığın belleği de harcarsınız . Şimdi, Java için yığın israfı, sistemin performansını düşürmenin ilk, en iyi yoludur, çünkü verimli çöp toplama (şu anda bu G1 ile değişebilir, ancak jüri en azından 2013'ün başından itibaren hala bu noktada değil gibi görünüyor) çok fazla yedek yığının olmasına bağlıdır. Yani, sorun var, çok az sayıda iş parçacığıyla ayarlayın, boş CPU'larınız ve düşük veriminiz var, çok fazla ayar yapın ve başka şekillerde bataklık yapın.

5) Düğüm'ün yaklaşımının "tasarımla daha hızlı" olduğu iddiasının mantığını kabul etmemin başka bir yolu daha var ve işte bu. Çoğu iş parçacığı modeli, daha uygun (değer yargısı uyarısı :) ve daha verimli (bir değer yargısı değil) önleyici modelin üzerine yerleştirilmiş zaman dilimli bir bağlam anahtarı modeli kullanır. Bu iki nedenden ötürü olur, ilk olarak, çoğu programcı öncelik önleme anlamıyor gibi görünüyor ve ikincisi, bir pencere ortamında iplik geçirmeyi öğrenirseniz, hoşunuza gitsin ya da sevmesin zamanlama var (elbette, bu ilk noktayı güçlendiriyor) Özellikle, Java'nın ilk sürümleri Windows'ta Solaris uygulamaları ve zaman dilimlemesinde öncelikli önleme kullandı. modeli her yerde zaman dilimi olarak değiştirdiler). Her neyse, alt satırda zaman dilimleme ek (ve potansiyel olarak gereksiz) bağlam anahtarları oluşturur. Her bağlam anahtarı CPU zamanını alır ve o zaman eldeki gerçek işte yapılabilecek işten etkili bir şekilde çıkarılır. Bununla birlikte, zaman diliminden dolayı bağlam değiştirme için harcanan zaman miktarı, oldukça tuhaf bir şey olmadıkça ve zamanın böyle olmasını beklemem için hiçbir neden yokken, toplam sürenin çok küçük bir yüzdesinden fazla olmamalıdır. basit web sunucusu). Yani, evet, zaman dilimlemeye dahil olan aşırı bağlam anahtarları verimsizdir (ve bunlar gerçekleşmez ve o zaman eldeki gerçek işte yapılabilecek işten etkili bir şekilde çıkarılır. Bununla birlikte, zaman diliminden dolayı bağlam değiştirme için harcanan zaman miktarı, oldukça tuhaf bir şey olmadıkça ve zamanın böyle olmasını beklemem için hiçbir neden yokken, toplam sürenin çok küçük bir yüzdesinden fazla olmamalıdır. basit web sunucusu). Yani, evet, zaman dilimlemeye dahil olan aşırı bağlam anahtarları verimsizdir (ve bunlar gerçekleşmez ve o zaman eldeki gerçek işte yapılabilecek işten etkili bir şekilde çıkarılır. Bununla birlikte, zaman diliminden dolayı bağlam değiştirme için harcanan zaman miktarı, oldukça tuhaf bir şey olmadıkça ve zamanın böyle olmasını beklemem için hiçbir neden yokken, toplam sürenin çok küçük bir yüzdesinden fazla olmamalıdır. basit web sunucusu). Yani, evet, zaman dilimlemede yer alan aşırı bağlam anahtarları verimsizdir (ve bunlarbir kural olarak çekirdek iş parçacıkları, btw), ancak fark, Düğüm için genellikle ima edilen performans iddialarında ima edilen tam sayı faktörlerinin türü değil, verimin yüzde birkaçı olacaktır.

Her neyse, hepsinin uzun ve aşırı olduğu için özür dilerim, ama şimdiye kadar tartışmanın hiçbir şey kanıtlamadığını hissediyorum ve bu durumlardan herhangi birinde birinden haber almaktan memnuniyet duyarım:

a) Düğümün neden daha iyi olması gerektiğine dair gerçek bir açıklama (yukarıda özetlediğim iki senaryonun ötesinde, birincisi (kötü ayarlama) şimdiye kadar gördüğüm tüm testlerin gerçek açıklaması olduğuna inanıyorum. ], aslında, bu konuda ne kadar düşünürsem, çok sayıda yığın tarafından kullanılan belleğin burada önemli olup olmadığını merak ediyorum. Modern iş parçacıkları için varsayılan yığın boyutları oldukça büyük olma eğilimindedir, ancak kapanışa dayalı olay sistemi sadece ihtiyaç duyulan şey olacaktır)

b) tercih edilen dişli sunucuya gerçekten şans tanıyan gerçek bir karşılaştırma ölçütü. En azından bu şekilde, iddiaların aslında yanlış olduğuna inanmayı bırakmalıyım;> ([değiştir] muhtemelen istediğimden daha güçlü, ancak performans avantajları için verilen açıklamaların en iyi şekilde eksik olduğunu hissediyorum ve gösterilen karşılaştırmalar makul değildir).

Şerefe, Toby


2
Konu ile ilgili bir sorun: RAM'e ihtiyaçları var. Çok meşgul bir sunucu birkaç bin iş parçacığı çalıştırabilir. Node.js iş parçacıklarını önler ve bu nedenle daha verimlidir. Verimlilik kodu daha hızlı çalıştırmak değildir. Kodun iş parçacıklarında mı yoksa bir olay döngüsünde mi çalıştığı önemli değildir. CPU için aynı. Ancak iş parçacıklarını ortadan kaldırırken RAM'den tasarruf ediyoruz: birkaç bin yığın yerine yalnızca bir yığın. Ayrıca bağlam anahtarlarını da kaydediyoruz.
nalply

3
Ancak düğüm, iş parçacıklarını ortadan kaldırmaz. Bunları hala çoğu web isteğinin gerektirdiği IO görevleri için dahili olarak kullanır.
Levi

1
Ayrıca düğüm geri aramaların kapanışlarını RAM'de saklar, bu yüzden nerede kazandığını göremiyorum.
Oleksandr Papchenko

@ levi Ancak nodejs “istek başına bir iş parçacığı” türünü kullanmaz. Muhtemelen asenkronize IO API'lerinin kullanımıyla ilgili karışıklığı önlemek için bir IO iş parçacığı kullanır (ve belki POSIX open()engelleme yapamaz?). Bu şekilde, geleneksel fork()/ pthread_create()istek üzerine modelin iş parçacıkları oluşturmak ve yok etmek zorunda kaldığı performans vuruşlarını amorti eder . Ve postscript a) 'da belirtildiği gibi, bu da yığın alanı sorununu amorti eder. Muhtemelen, 16 IO iş parçacığı ile binlerce istekte bulunabilirsiniz.
binki

"Modern iş parçacığı için varsayılan yığın boyutları oldukça büyük olma eğilimindedir, ancak kapanış tabanlı bir olay sistemi tarafından ayrılan bellek yalnızca gereken şey olurdu" Bunların aynı sırada olması gerektiği izlenimini alıyorum. Kapanışlar ucuz değildir, çalışma zamanı tek iş parçacıklı uygulamanın tüm çağrı ağacını bellekte tutmak zorunda kalacaktır ("öyleyse" yığınları taklit ") ve ilgili yaprak olarak bir ağaç yaprağı serbest bırakıldığında temizlenebilir "çözümlenir". Bu, çöp toplanamayan yığın temizleme malzemelerine yapılan çok sayıda referansı içerecek ve temizleme zamanında performansı etkileyecektir.
David Tonhofer

14

Ne anlamıyorum Node.js hala iş parçacığı kullanıyor nokta.

Ryan, bloke olan parçalar için (node.js öğelerinin çoğu bloke olmayan IO kullanır) iplik kullanır, çünkü bazı bölümlerin bloke edilmemesi zor olur. Ama inanıyorum ki Ryan dilek her şeyi engellemeyecek. Açık slayt 63 (dahili tasarımı) Ryan kullanır bkz libev engellenmeyen için (zaman uyumsuz olay bildirimi soyutlar kütüphane) eventloop . Olay döngüsü düğümü nedeniyle, bağlam değiştirme, bellek tüketimi vb. Azaltan daha az iş parçacığı gerekir.


11

İş parçacıkları yalnızca asenkron özelliği olmayan işlevlerle başa çıkmak için kullanılır stat().

stat()Fonksiyon her zaman çok ana iş parçacığı (olay döngü) engellemeden gerçek çağrıyı gerçekleştirmek için bir iş parçacığı kullanımı ihtiyaçlarını node.js, engelliyor. Potansiyel olarak, bu tür işlevleri çağırmanız gerekmiyorsa, iş parçacığı havuzundan hiçbir iş parçacığı kullanılmayacaktır.


7

Node.js'nin dahili çalışmaları hakkında hiçbir şey bilmiyorum, ancak bir olay döngüsü kullanmanın dişli G / Ç işleminden nasıl daha iyi performans gösterdiğini görebiliyorum. Bir disk isteği düşünün, bana staticFile.x verin, dosya için 100 istek yapın. Her istek normalde bu dosyayı geri alan bir iş parçacığı alır, bu 100 iş parçacığıdır.

Şimdi, ilk istek bir yayımcı nesnesi haline gelen bir iş parçacığı oluşturduğunu hayal edin, diğer 99 isteğin ilk önce staticFile.x için bir yayıncı nesnesi olup olmadığına bakın, eğer öyleyse, işini yaparken dinleyin, aksi takdirde yeni bir iş parçacığı başlatın ve böylece yeni yayıncı nesnesi.

Tek bir iş parçacığı tamamlandığında, staticFile.x dosyasını 100 dinleyiciye iletir ve kendisini yok eder, böylece bir sonraki istek yeni ve yeni bir iş parçacığı ve yayıncı nesnesi oluşturur.

Bu yüzden yukarıdaki örnekte 100 iş parçacığı ile 1 iş parçacığı, aynı zamanda 100 disk araması yerine 1 disk araması, kazanç oldukça fenominal olabilir. Ryan akıllı bir adam!

Bakmanın bir başka yolu, filmin başlangıcındaki örneklerinden biridir. Onun yerine:

pseudo code:
result = query('select * from ...');

Yine, bir veritabanına karşı 100 ayrı sorgu ...:

pseudo code:
query('select * from ...', function(result){
    // do stuff with result
});

Bir sorgu zaten gidiyorsa, diğer eşit sorgular bandwagon'a atlar, böylece tek bir veritabanı gidiş dönüşünde 100 sorgunuz olabilir.


3
Veritabanı şey daha çok diğer istekleri tutarken (veritabanını kullanabilir veya kullanamayabilir) yanıtı beklememek değil, bir şey isteyin ve geri geldiğinde sizi aramasına izin vermektir. Onları birbirine bağladığını düşünmüyorum, çünkü bu, yanıtı takip etmek oldukça zor olurdu. Ayrıca, bir bağlantıda birden fazla arabelleksiz yanıt vermenizi sağlayan herhangi bir MySQL arayüzü olduğunu düşünmüyorum (??)
Tor Valamo

Olay döngülerinin nasıl daha fazla verimlilik sunabileceğini açıklamak için sadece soyut bir örnek, nodejs ekstra modüller olmadan DB'lerle hiçbir şey yapmıyor;)
BGerrissen

1
Evet benim yorum daha tek bir veritabanı gidiş dönüş 100 sorgu doğru oldu. : p
Tor Valamo

2
Merhaba BGerrissen: güzel gönderi. Yani, bir sorgu yürütülürken, benzer sorguları yukarıdaki staticFile.X örneği gibi "dinleyici" olur? örneğin, aynı sorguyu alan 100 kullanıcı, yalnızca bir sorgu yürütülür ve diğerleri 99 ilk sorguyu dinler mi? Teşekkürler !
CHAPa

1
Düğümler otomatik olarak işlev çağrılarını veya başka bir şeyi hatırlar gibi geliyor. Artık JavaScript'in olay döngüsü modelinde paylaşılan bellek senkronizasyonu konusunda endişelenmeniz gerekmediğinden, bellekteki şeyleri güvenli bir şekilde önbelleğe almak daha kolaydır. Ancak bu, nodejs'in sihirli bir şekilde sizin için yaptığı veya bunun, sorulan performans geliştirme türü olduğu anlamına gelmez.
binki
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.