Rumah > Tutorial sistem > LINUX > teks badan

Membandingkan prestasi I/O pelayan Node, PHP, Java dan Go

PHPz
Lepaskan: 2024-01-14 14:36:06
ke hadapan
736 orang telah melayarinya
Pengenalan Memahami model input/output (I/O) aplikasi bermaksud perbezaan antara beban pemprosesan yang dirancang dan senario penggunaan dunia sebenar yang kejam. Jika aplikasi agak kecil dan tidak memberikan beban yang tinggi, ia mungkin mempunyai sedikit impak. Tetapi apabila beban pada aplikasi anda meningkat secara beransur-ansur, menggunakan model I/O yang salah boleh menyebabkan anda mengalami banyak perangkap dan parut.

Seperti kebanyakan senario di mana terdapat pelbagai penyelesaian, perkara utama bukanlah yang mana lebih baik, tetapi memahami cara membuat pertukaran. Mari kita lihat landskap I/O dan lihat apa yang boleh kita curi daripadanya.

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Dalam artikel ini, kami akan membandingkan Node, Java, Go, dan PHP masing-masing dengan Apache, membincangkan cara bahasa yang berbeza ini memodelkan I/O mereka, kelebihan dan kekurangan setiap model, dan membuat beberapa kesimpulan awal. Jika anda bimbang tentang prestasi I/O aplikasi web anda yang seterusnya, maka anda telah menemui artikel yang betul.

Asas I/O: Kajian pantas

Untuk memahami faktor yang berkait rapat dengan I/O, kita mesti menyemak konsep asas sistem pengendalian terlebih dahulu. Walaupun anda tidak akan berurusan dengan kebanyakan konsep ini secara langsung, anda telah menanganinya secara tidak langsung melalui persekitaran masa jalan aplikasi. Dan syaitan ada dalam butirannya.

Panggilan sistem

Pertama, kami mempunyai panggilan sistem, yang boleh digambarkan seperti ini:

  • Atur cara anda (dalam "tanah pengguna", seperti yang mereka katakan) mesti membiarkan kernel sistem pengendalian menjalankan operasi I/O sendiri.
  • "panggilan sistem" (syscall) bermakna program anda meminta kernel untuk melakukan sesuatu. Sistem pengendalian yang berbeza mempunyai butiran pelaksanaan yang berbeza bagi panggilan sistem, tetapi konsep asasnya adalah sama. Ini akan mempunyai beberapa arahan khusus yang memindahkan kawalan daripada program anda ke kernel (serupa dengan panggilan fungsi tetapi dengan beberapa sos khas yang direka untuk mengendalikan senario ini). Biasanya, panggilan sistem disekat, bermakna program anda perlu menunggu kernel untuk kembali ke kod anda.
  • Inti menjalankan operasi I/O peringkat rendah pada apa yang kita panggil peranti fizikal (cakera keras, kad rangkaian, dll.) dan bertindak balas kepada panggilan sistem. Dalam dunia nyata, kernel mungkin perlu melakukan banyak perkara untuk melengkapkan permintaan anda, termasuk menunggu peranti bersedia, mengemas kini keadaan dalamannya, dsb., tetapi sebagai pembangun aplikasi, anda tidak perlu risau tentang itu. Begini cara kernel berfungsi.

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Menyekat panggilan dan panggilan tidak menyekat

Baiklah, saya baru sahaja mengatakan di atas bahawa panggilan sistem menyekat Secara umumnya, ini adalah benar. Walau bagaimanapun, sesetengah panggilan diklasifikasikan sebagai "tidak menyekat", bermakna kernel menerima permintaan anda, meletakkannya dalam baris gilir atau penimbal di suatu tempat, dan kemudian kembali serta-merta tanpa menunggu panggilan I/O sebenar. Jadi ia hanya "menyekat" untuk tempoh masa yang sangat singkat, cukup untuk mengantri permintaan anda.

Berikut ialah beberapa contoh (panggilan sistem Linux) untuk membantu menjelaskan: -read() ialah panggilan menyekat - anda menghantarnya ke pemegang fail dan penimbal untuk menyimpan data yang dibaca, dan kemudian panggilan itu akan Kembali apabila data itu sedia. Ambil perhatian bahawa pendekatan ini mempunyai kelebihan keanggunan dan kesederhanaan. -epoll_create() , epoll_ctl() , dan epoll_wait() masing-masing, ialah panggilan yang membolehkan anda membuat set pemegang untuk mendengar, menambah/mengalih keluar pemegang daripada set itu, dan kemudian tunggu sehingga terdapat aktiviti Baru disekat. Ini membolehkan anda mengawal satu siri operasi I/O dengan cekap melalui benang. Ini bagus jika anda memerlukan ciri ini, tetapi seperti yang anda lihat, ia sememangnya agak rumit untuk digunakan.

Adalah penting untuk memahami susunan magnitud perbezaan masa di sini. Jika teras CPU berjalan pada 3GHz, tanpa pengoptimuman, ia melaksanakan 3 bilion gelung sesaat (atau 3 gelung setiap nanosaat). Panggilan sistem tanpa sekatan mungkin mengambil masa mengikut urutan 10 nanosaat untuk diselesaikan - atau "agak sedikit nanosaat". Menyekat panggilan yang menerima maklumat melalui rangkaian mungkin mengambil lebih banyak masa - contohnya 200 milisaat (0.2 saat). Sebagai contoh, andaikan panggilan tidak menyekat mengambil masa 20 nanosaat, maka panggilan menyekat mengambil masa 200,000,000 nanosaat. Untuk menyekat panggilan, program anda menunggu 10 juta kali lebih lama.

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Inti menyediakan dua kaedah: menyekat I/O ("baca daripada sambungan rangkaian dan berikan saya data") dan I/O tidak menyekat ("beritahu saya apabila sambungan rangkaian ini mempunyai data baharu"). Bergantung pada mekanisme yang digunakan, masa menyekat proses panggilan yang sepadan jelas berbeza.

Penjadualan

Perkara kritikal ketiga ialah apa yang perlu dilakukan apabila sejumlah besar benang atau proses mula disekat.

Untuk tujuan kami, tidak banyak perbezaan antara benang dan proses. Malah, perbezaan berkaitan pelaksanaan yang paling jelas ialah benang berkongsi memori yang sama, manakala setiap proses mempunyai ruang ingatan sendiri, menjadikan proses berasingan sering menduduki sejumlah besar memori. Tetapi apabila kita bercakap tentang penjadualan, ia akhirnya bermuara kepada senarai acara (benang dan proses yang sama) di mana setiap acara perlu mendapatkan secebis masa pelaksanaan pada teras CPU yang tersedia. Jika anda mempunyai 300 utas berjalan dan anda menjalankan 8 teras, anda perlu merebakkan masa itu supaya setiap utas mendapat sesuatu dengan menjalankan setiap teras untuk tempoh masa yang singkat dan kemudian beralih ke perkongsian masanya. Ini dicapai dengan "penukaran konteks", yang membolehkan CPU beralih dari satu utas/proses yang sedang berjalan ke seterusnya.

Suis konteks ini mempunyai kos - ia mengambil sedikit masa. Apabila pantas, ia mungkin kurang daripada 100 nanosaat, tetapi bukan perkara biasa untuk mengambil 1000 nanosaat atau lebih bergantung pada butiran pelaksanaan, kelajuan/seni bina pemproses, cache CPU, dsb.

Semakin banyak rangkaian (atau proses) terdapat, semakin banyak suis konteks yang ada. Apabila kita bercakap tentang beribu-ribu benang dan setiap suis mengambil masa ratusan nanosaat, ia akan menjadi sangat perlahan.

Walau bagaimanapun, panggilan tidak menyekat pada dasarnya memberitahu kernel "hubungi saya hanya apabila anda mempunyai beberapa data baharu atau terdapat peristiwa pada mana-mana sambungan ini." Panggilan tidak menyekat ini direka untuk mengendalikan beban I/O yang besar dengan cekap dan mengurangkan suis konteks.

Adakah anda masih membaca artikel ini setakat ini? Kerana sekarang datang bahagian yang menyeronokkan: mari kita lihat bagaimana beberapa bahasa fasih menggunakan alat ini dan buat beberapa kesimpulan tentang pertukaran antara kemudahan penggunaan dan prestasi... dan komen menarik yang lain.

Sila ambil perhatian bahawa walaupun contoh yang ditunjukkan dalam siaran ini adalah remeh (dan tidak lengkap, hanya menunjukkan bahagian kod yang berkaitan), akses pangkalan data, sistem caching luaran (memcache, dll. semua) dan yang memerlukan I/O Semuanya berakhir melaksanakan beberapa operasi I/O asas, yang mempunyai kesan yang sama seperti contoh yang ditunjukkan. Begitu juga, untuk situasi di mana I/O digambarkan sebagai "menyekat" (PHP, Java), pembacaan dan penulisan permintaan dan respons HTTP sendiri menyekat panggilan: sekali lagi, lebih banyak I/O disembunyikan dalam sistem O dan yang disertakan bersamanya. isu prestasi perlu dipertimbangkan.

Terdapat banyak faktor yang perlu dipertimbangkan semasa memilih bahasa pengaturcaraan untuk projek anda. Apabila anda hanya mempertimbangkan prestasi, terdapat lebih banyak faktor yang perlu dipertimbangkan. Walau bagaimanapun, jika kebimbangan anda adalah bahawa program anda terutamanya terikat I/O, dan jika prestasi I/O adalah penting untuk projek anda, maka ini adalah perkara yang perlu anda ketahui. Pendekatan "kekalkannya mudah": PHP.

Pada tahun 90-an, ramai orang memakai kasut Converse dan menulis skrip CGI dalam Perl. Kemudian PHP muncul, dan ramai orang suka menggunakannya, yang menjadikannya lebih mudah untuk membuat halaman web dinamik.

Model yang digunakan oleh PHP agak mudah. Terdapat beberapa variasi, tetapi pada asasnya pelayan PHP kelihatan seperti:

Permintaan HTTP datang daripada penyemak imbas pengguna dan mengakses pelayan web Apache anda. Apache mencipta proses berasingan untuk setiap permintaan, menggunakannya semula dengan beberapa pengoptimuman untuk meminimumkan bilangan kali ia perlu melaksanakan (proses mencipta adalah agak perlahan). Apache memanggil PHP dan menyuruhnya menjalankan fail .php yang sepadan pada cakera. Kod PHP melaksanakan dan membuat beberapa panggilan I/O yang menyekat. Jika file_get_contents() dipanggil dalam PHP, ia akan mencetuskan panggilan sistem read() di belakang tabir dan menunggu keputusan dikembalikan.

Sudah tentu, kod sebenar hanya dibenamkan dalam halaman anda, dan operasi menyekat:

<?php

// 阻塞的文件I/O
$file_data = file_get_contents('/path/to/file.dat');

// 阻塞的网络I/O
$curl = curl_init('http://example.com/example-microservice');
$result = curl_exec($curl);

// 更多阻塞的网络I/O
$result = $db->query('SELECT id, data FROM examples ORDER BY id DESC limit 100');

?>
Salin selepas log masuk

Mengenai cara ia berintegrasi dengan sistem, seperti ini:

Node、PHP、Java 和 Go 服务端 I/O 性能PK

相当简单:一个请求,一个进程。I/O是阻塞的。优点是什么呢?简单,可行。那缺点是什么呢?同时与20,000个客户端连接,你的服务器就挂了。由于内核提供的用于处理大容量I/O(epoll等)的工具没有被使用,所以这种方法不能很好地扩展。更糟糕的是,为每个请求运行一个单独的过程往往会使用大量的系统资源,尤其是内存,这通常是在这样的场景中遇到的第一件事情。

注意:Ruby使用的方法与PHP非常相似,在广泛而普遍的方式下,我们可以将其视为是相同的。

多线程的方式:Java

所以就在你买了你的第一个域名的时候,Java来了,并且在一个句子之后随便说一句“dot com”是很酷的。而Java具有语言内置的多线程(特别是在创建时),这一点非常棒。

大多数Java网站服务器通过为每个进来的请求启动一个新的执行线程,然后在该线程中最终调用作为应用程序开发人员的你所编写的函数。

在Java的Servlet中执行I/O操作,往往看起来像是这样:

public void doGet(HttpServletRequest request,  
    HttpServletResponse response) throws ServletException, IOException
{

    // 阻塞的文件I/O
    InputStream fileIs = new FileInputStream("/path/to/file");

    // 阻塞的网络I/O
    URLConnection urlConnection = (new URL("https://example.com/example-microservice")).openConnection();
    InputStream netIs = urlConnection.getInputStream();

    // 更多阻塞的网络I/O
    out.println("...");
}
Salin selepas log masuk

由于我们上面的doGet 方法对应于一个请求并且在自己的线程中运行,而不是每次请求都对应需要有自己专属内存的单独进程,所以我们会有一个单独的线程。这样会有一些不错的优点,例如可以在线程之间共享状态、共享缓存的数据等,因为它们可以相互访问各自的内存,但是它如何与调度进行交互的影响,仍然与前面PHP例子中所做的内容几乎一模一样。每个请求都会产生一个新的线程,而在这个线程中的各种I/O操作会一直阻塞,直到这个请求被完全处理为止。为了最小化创建和销毁它们的成本,线程会被汇集在一起,但是依然,有成千上万个连接就意味着成千上万个线程,这对于调度器是不利的。

一个重要的里程碑是,在Java 1.4 版本(和再次显著升级的1.7 版本)中,获得了执行非阻塞I/O调用的能力。大多数应用程序,网站和其他程序,并没有使用它,但至少它是可获得的。一些Java网站服务器尝试以各种方式利用这一点; 然而,绝大多数已经部署的Java应用程序仍然如上所述那样工作。

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Java让我们更进了一步,当然对于I/O也有一些很好的“开箱即用”的功能,但它仍然没有真正解决问题:当你有一个严重I/O绑定的应用程序正在被数千个阻塞线程狂拽着快要坠落至地面时怎么办。

作为一等公民的非阻塞I/O:Node

当谈到更好的I/O时,Node.js无疑是新宠。任何曾经对Node有过最简单了解的人都被告知它是“非阻塞”的,并且它能有效地处理I/O。在一般意义上,这是正确的。但魔鬼藏在细节中,当谈及性能时这个巫术的实现方式至关重要。

本质上,Node实现的范式不是基本上说“在这里编写代码来处理请求”,而是转变成“在这里写代码开始处理请求”。每次你都需要做一些涉及I/O的事情,发出请求或者提供一个当完成时Node会调用的回调函数。

在求中进行I/O操作的典型Node代码,如下所示:

http.createServer(function(request, response) {  
    fs.readFile('/path/to/file', 'utf8', function(err, data) {
        response.end(data);
    });
});
Salin selepas log masuk

可以看到,这里有两个回调函数。第一个会在请求开始时被调用,而第二个会在文件数据可用时被调用。

这样做的基本上给了Node一个在这些回调函数之间有效地处理I/O的机会。一个更加相关的场景是在Node中进行数据库调用,但我不想再列出这个烦人的例子,因为它是完全一样的原则:启动数据库调用,并提供一个回调函数给Node,它使用非阻塞调用单独执行I/O操作,然后在你所要求的数据可用时调用回调函数。这种I/O调用队列,让Node来处理,然后获取回调函数的机制称为“事件循环”。它工作得非常好。

Node、PHP、Java 和 Go 服务端 I/O 性能PK

然而,这个模型中有一道关卡。在幕后,究其原因,更多是如何实现JavaScript V8 引擎(Chrome的JS引擎,用于Node)1,而不是其他任何事情。你所编写的JS代码全部都运行在一个线程中。思考一下。这意味着当使用有效的非阻塞技术执行I/O时,正在进行CPU绑定操作的JS可以在运行在单线程中,每个代码块阻塞下一个。 一个常见的例子是循环数据库记录,在输出到客户端前以某种方式处理它们。以下是一个例子,演示了它如何工作:

var handler = function(request, response) {

    connection.query('SELECT ...', function (err, rows) {

        if (err) { throw err };

        for (var i = 0; i < rows.length; i++) {
            // 对每一行纪录进行处理
        }

        response.end(...); // 输出结果

    })

};
Salin selepas log masuk

虽然Node确实可以有效地处理I/O,但上面的例子中的for 循环使用的是在你主线程中的CPU周期。这意味着,如果你有10,000个连接,该循环有可能会让你整个应用程序慢如蜗牛,具体取决于每次循环需要多长时间。每个请求必须分享在主线程中的一段时间,一次一个。

这个整体概念的前提是I/O操作是最慢的部分,因此最重要是有效地处理这些操作,即使意味着串行进行其他处理。这在某些情况下是正确的,但不是全都正确。

另一点是,虽然这只是一个意见,但是写一堆嵌套的回调可能会令人相当讨厌,有些人认为它使得代码明显无章可循。在Node代码的深处,看到嵌套四层、嵌套五层、甚至更多层级的嵌套并不罕见。

我们再次回到了权衡。如果你主要的性能问题在于I/O,那么Node模型能很好地工作。然而,它的阿喀琉斯之踵(

真正的非阻塞:Go

在进入Go这一章节之前,我应该披露我是一名Go粉丝。我已经在许多项目中使用Go,是其生产力优势的公开支持者,并且在使用时我在工作中看到了他们。

也就是说,我们来看看它是如何处理I/O的。Go语言的一个关键特性是它包含自己的调度器。并不是每个线程的执行对应于一个单一的OS线程,Go采用的是“goroutines”这一概念。Go运行时可以将一个goroutine分配给一个OS线程并使其执行,或者把它挂起而不与OS线程关联,这取决于goroutine做的是什么。来自Go的HTTP服务器的每个请求都在单独的Goroutine中处理。

此调度器工作的示意图,如下所示:

Node、PHP、Java 和 Go 服务端 I/O 性能PK

这是通过在Go运行时的各个点来实现的,通过将请求写入/读取/连接/等实现I/O调用,让当前的goroutine进入睡眠状态,当可采取进一步行动时用信息把goroutine重新唤醒。

实际上,除了回调机制内置到I/O调用的实现中并自动与调度器交互外,Go运行时做的事情与Node做的事情并没有太多不同。它也不受必须把所有的处理程序代码都运行在同一个线程中这一限制,Go将会根据其调度器的逻辑自动将Goroutine映射到其认为合适的OS线程上。最后代码类似这样:

func ServeHTTP(w http.ResponseWriter, r *http.Request) {

    // 这里底层的网络调用是非阻塞的
    rows, err := db.Query("SELECT ...")

    for _, row := range rows {
        // 处理rows
        // 每个请求在它自己的goroutine中
    }

    w.Write(...) // 输出响应结果,也是非阻塞的

}
Salin selepas log masuk

正如你在上面见到的,我们的基本代码结构像是更简单的方式,并且在背后实现了非阻塞I/O。

在大多数情况下,这最终是“两个世界中最好的”。非阻塞I/O用于全部重要的事情,但是你的代码看起来像是阻塞,因此往往更容易理解和维护。Go调度器和OS调度器之间的交互处理了剩下的部分。这不是完整的魔法,如果你建立的是一个大型的系统,那么花更多的时间去理解它工作原理的更多细节是值得的; 但与此同时,“开箱即用”的环境可以很好地工作和很好地进行扩展。

Go可能有它的缺点,但一般来说,它处理I/O的方式不在其中。

谎言,诅咒的谎言和基准

对这些各种模式的上下文切换进行准确的定时是很困难的。也可以说这对你来没有太大作用。所以取而代之,我会给出一些比较这些服务器环境的HTTP服务器性能的基准。请记住,整个端对端的HTTP请求/响应路径的性能与很多因素有关,而这里我放在一起所提供的数据只是一些样本,以便可以进行基本的比较。

对于这些环境中的每一个,我编写了适当的代码以随机字节读取一个64k大小的文件,运行一个SHA-256哈希N次(N在URL的查询字符串中指定,例如.../test.php?n=100 ),并以十六进制形式打印生成的散列。我选择了这个示例,是因为使用一些一致的I/O和一个受控的方式增加CPU使用率来运行相同的基准测试是一个非常简单的方式。

Berkenaan penggunaan alam sekitar, sila rujuk titik penanda aras ini untuk butiran lanjut.

Pertama, mari lihat beberapa contoh konkurensi rendah. Menjalankan 2000 lelaran, 300 permintaan serentak dan pencincangan hanya sekali bagi setiap permintaan (N = 1), kami mendapat:

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Masa ialah purata bilangan milisaat yang diperlukan untuk melengkapkan permintaan antara semua permintaan serentak. Lebih rendah lebih baik.

Sukar untuk membuat kesimpulan daripada hanya satu graf, tetapi bagi saya ia kelihatan berkaitan dengan perkara seperti ketersambungan dan pengiraan, kita melihat bahawa masa lebih berkaitan dengan pelaksanaan umum bahasa itu sendiri, jadi ia lebih kepada I/O. Ambil perhatian bahawa bahasa yang dianggap "bahasa skrip" (input sewenang-wenangnya, ditafsirkan secara dinamik) menunjukkan prestasi yang paling perlahan.

Tetapi apa yang berlaku jika anda meningkatkan N kepada 1000 dan masih mempunyai 300 permintaan serentak - beban yang sama, tetapi 100 kali lelaran cincang (peningkatan ketara dalam beban CPU):

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Masa ialah purata bilangan milisaat yang diperlukan untuk melengkapkan permintaan antara semua permintaan serentak. Lebih rendah lebih baik.

Tiba-tiba, prestasi Node menurun dengan ketara apabila operasi intensif CPU dalam setiap permintaan menyekat satu sama lain. Menariknya, dalam ujian ini, PHP menunjukkan prestasi yang lebih baik (berbanding dengan bahasa lain) dan mengalahkan Java. (Perlu diingat bahawa dalam PHP, di mana pelaksanaan SHA-256 ditulis dalam C, laluan pelaksanaan mengambil lebih banyak masa dalam gelung ini kerana kali ini kita melakukan 1000 lelaran cincang).

Sekarang mari cuba 5000 sambungan serentak (dan N = 1) - atau hampir dengan itu. Malangnya, untuk kebanyakan persekitaran ini, kadar kegagalan tidak ketara. Untuk carta ini, kami akan menumpukan pada jumlah bilangan permintaan sesaat. Lebih tinggi lagi bagus:

Node、PHP、Java 和 Go 服务端 I/O 性能PK

Jumlah bilangan permintaan sesaat. Lagi tinggi lagi bagus.

Foto ini kelihatan berbeza sama sekali. Ini adalah tekaan, tetapi nampaknya untuk volum sambungan yang tinggi, overhed yang dikaitkan dengan melahirkan proses baharu setiap sambungan, dan memori tambahan yang dikaitkan dengan PHP + Apache nampaknya menjadi faktor utama dan mengehadkan prestasi PHP. Jelas sekali, Go adalah pemenang di sini, diikuti oleh Java dan Node, dan akhirnya PHP.

Kesimpulan

Ringkasnya, adalah jelas bahawa apabila bahasa berkembang, begitu juga penyelesaian untuk aplikasi besar yang mengendalikan sejumlah besar I/O.

Demi keadilan, mengetepikan huraian artikel ini buat masa ini, PHP dan Java mempunyai pelaksanaan I/O tidak menyekat yang boleh digunakan dalam aplikasi web. Tetapi kaedah ini tidak lazim seperti kaedah di atas, dan overhed operasi atendan untuk menyelenggara pelayan menggunakan kaedah ini perlu dipertimbangkan. Apatah lagi bahawa kod anda mesti distrukturkan dengan cara yang sesuai untuk persekitaran ini "biasa" PHP atau aplikasi web Java secara amnya tidak mengalami perubahan ketara dalam persekitaran tersebut.

Sebagai perbandingan, jika anda hanya mempertimbangkan beberapa faktor penting yang mempengaruhi prestasi dan kemudahan penggunaan, anda boleh mendapatkan:

Bahasa Benang atau proses Tidak menyekat I/O Kemudahan penggunaan
PHP Proses Tidak
Jawa Benang Tersedia Perlukan panggilan balik
Node.js Benang Ya Perlukan panggilan balik
Pergi Benang (Goroutine) Ya Tiada panggilan balik diperlukan

Benang biasanya lebih cekap memori daripada proses kerana ia berkongsi ruang memori yang sama, manakala proses tidak. Digabungkan dengan faktor yang berkaitan dengan I/O tidak menyekat, apabila kita beralih ke senarai ke permulaan umum kerana ia berkaitan dengan peningkatan I/O, seseorang boleh melihat sekurang-kurangnya faktor yang sama seperti yang dipertimbangkan di atas. Jika saya terpaksa memilih pemenang antara permainan di atas, ia pastinya Go.

Secara praktikal, persekitaran yang anda pilih untuk membina aplikasi anda berkait rapat dengan kebiasaan pasukan anda dengan persekitaran tersebut dan produktiviti keseluruhan yang boleh dicapai. Oleh itu, mungkin tidak masuk akal bagi setiap pasukan untuk melompat masuk dan mula membangunkan aplikasi dan perkhidmatan web dalam Node atau Go. Malah, mencari kebiasaan dengan pembangun atau pasukan dalaman sering disebut sebagai sebab utama untuk tidak menggunakan bahasa yang berbeza dan/atau persekitaran yang berbeza. Dalam erti kata lain, masa telah berubah secara mendadak dalam tempoh lima belas tahun yang lalu.

Semoga perkara di atas membantu anda mendapatkan gambaran yang lebih jelas tentang perkara yang berlaku di sebalik tabir dan memberi anda beberapa idea tentang cara mengendalikan kebolehskalaan dunia sebenar aplikasi anda. Masukan gembira, keluaran gembira!

Atas ialah kandungan terperinci Membandingkan prestasi I/O pelayan Node, PHP, Java dan Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:linuxprobe.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!