GVKun编程网logo

怎样用 NodeJS 充分利用多核 CPU 的资源(node如何利用多核)

17

如果您想了解怎样用NodeJS充分利用多核CPU的资源的相关知识,那么本文是一篇不可错过的文章,我们将对node如何利用多核进行全面详尽的解释,并且为您提供关于3.如何理解开多线程可以充分利用CPU?

如果您想了解怎样用 NodeJS 充分利用多核 CPU 的资源的相关知识,那么本文是一篇不可错过的文章,我们将对node如何利用多核进行全面详尽的解释,并且为您提供关于3.如何理解开多线程可以充分利用CPU?、c# – CPU未充分利用.由于阻塞I / O?、C++并发编程:如何利用多核CPU实现并发?、Golang能否充分利用多核处理器的优势?的有价值的信息。

本文目录一览:

怎样用 NodeJS 充分利用多核 CPU 的资源(node如何利用多核)

怎样用 NodeJS 充分利用多核 CPU 的资源(node如何利用多核)

// 每日前端夜话 第509篇
// 正文共:1600 字
// 预计阅读时间:9 分钟

介绍

单个 Node.js 程序的实例仅在一个线程上运行,因此无法充分利用 CPU 的多核系统。有时你可能需要启动 Node.js 进程集群来利用本地计算机或生产服务器上的每个 CPU 内核。

在处理 API 或基于 ExpressJS 的HTTP服务器时,这个问题尤其重要。

幸运的是,Node.js 有一个名为 Cluster 的核心模块,它能够帮助我们在 CPU 的所有核心上运行 Node.js 程序。

在本文中,我们将会用 Node.js 实现一个 ExpressJS HTTP 服务器,并在每个 CPU 内核上创建一个唯一的实例。这样,由于每个其CPU 核心实例都会提供可能的并发请求数,因此 HTTP 服务器的吞吐量将会大大增加。

目录

  • 创建 Express HTTP 服务器
  • 在多个 CPU 核心上运行服务器

创建 Express HTTP 服务器

我们要做的第一件事是启动并运行 HTTP 服务器。如果你已经有了一个可用的 ExpressJS 服务器,则可以跳至下一部分:在多核 CPU 上运行服务器。

我们将用 ExpressJS 来快速创建一个高效而简单的服务器。如果尚未安装 npm 软件包,则可以用以下命令进行安装:

$ npm install --save express

然后把下面的代码添加到要你的的 Node.js 文件中:

const express = require("express")
const PORT = process.env.PORT || 5000
const app = express()
app.listen(PORT, function ({
  console.log(`Express server listening on port ${PORT}`)
})

首先,我们 require() 先前安装的 Express npm 软件包。

然后,我们创建一个 PORT 变量,该变量可以是当前的 process.env.PORT 的值,也可以是 5000。然后用express() 方法创建一个 express 实例,并将其保存在 app 变量中。

最添加 app.listen() 函数,用于启动 Express 程序,并告诉它侦听我们指定的 PORT

通过命令行运行代码时,应该看到类似的内容输出到控制台:

Output:
Express server listening on port 5000

很好!现在我们启动 Express HTTP 服务器。

在多个 CPU 核心上运行服务器

在本节中,我们会把 Express 服务器运行在 CPU 的多个核心上!

为了帮助我们实现这一目标,我们将使用Node.js模块 OS 和 Cluster 。用 OS 模块来检测系统有多少个 CPU 核,用 Cluster 模块来创建多个子进程,我们的 HTTP 服务器可以并行运行这些子进程。

由于这些是核心模块,因此不需要安装任何 npm 包,并且可以将它们 require()到我们的代码中。

我将为你提供完整的代码,并在随后进行解释,因此,如果你看得一头雾水,也没有关系。

这是完整的代码:

const express = require("express")
const os = require("os")
const cluster = require("cluster")

const PORT = process.env.PORT || 5000

const clusterWorkerSize = os.cpus().length

if (clusterWorkerSize > 1) {
  if (cluster.isMaster) {
    for (let i=0; i < clusterWorkerSize; i++) {
      cluster.fork()
    }
    cluster.on("exit"function(worker{
      console.log("Worker", worker.id, " has exitted.")
    })
  } else {
    const app = express()
    app.listen(PORT, function ({
      console.log(`Express server listening on port ${PORT} and worker ${process.pid}`)
    })
  }
else {
  const app = express()
  app.listen(PORT, function ({
    console.log(`Express server listening on port ${PORT} with the single worker ${process.pid}`)
  })
}

代码中做了很多事情,所以让我们解释它的每一个部分。

首先是 require() express 包以及 Node.js 的两个核心模块 oscluster

接下来,创建一个  PORT  变量,并为其分配当前 process.env.PORT 编号或 5000 的值。我们稍后将在启动时用到它。

然后,我们创建一个名为 clusterWorkerSize 的变量来表示系统的 CPU 数量。可以用 os.cpus().length方法获得这个数字。有关 os.cpus() 方法的更多信息可查看 Node.js 文档。

我们创建一个了 if...else语句,用 clusterWorkerSize 值检查 CPU 是否有多个核。如果 CPU 数量大于 1,我们就继续创建集群。但是如果运行代码的计算机上只有一个 CPU 核心,则以本教程第一步中的方式启动 Express 程序。

假设我们的机器有多个 CPU 核心,那么就要创建另一个 if...else 语句,检查该语句是否为集群中已运行的第一个进程。用 cluster.isMaster() 方法检查是否返回 truefalse

如果是第一个运行的进程,我们将用 cluster.fork() 为计算机上的每个 CPU 核产生一个新的工作进程。我们还添加了一个事件侦听器,该侦听器将在工作进程退出时输出一条消息,以便我们知道何时出现问题或意外。

值得注意的是,主进程用于侦听 HTTP 服务器的端口,并在工作进程之间平衡所有请求的负载。

产生所有工作进程后,我们将在创建的每个工作进程上创建一个程序的新实例。如果你的计算机有 2 个 CPU 核,则将会创建该程序的 2 个实例。

运行程序时,应该能够在控制台上看到以下内容:

Output:

Express server listening on port 5000 and worker 10801
Express server listening on port 5000 and worker 10802
Express server listening on port 5000 and worker 10803
Express server listening on port 5000 and worker 10804

输出将根据 CPU 核的数量而有所不同。

现在你有了一个能够在多核 CPU 上运行的 HTTP 服务器!

总结

cluster 模块使我们能够轻松创建子进程,从而为 Node.js 提供了使用 CPU 所提供的全部功能所急需的功能。并且它还在后台为在主进程和工作进程之间进行通信做了大量工作。

在读完本文之后,你现在应该知道该如何使用这个模块在多个 CPU 核心上运行 Express HTTP 服务器。有了这些知识,你将能够更好地管理和扩展你的应用。



强力推荐前端面试刷题神器



精彩文章回顾,点击直达




本文分享自微信公众号 - 前端先锋(jingchengyideng)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

3.如何理解开多线程可以充分利用CPU?

3.如何理解开多线程可以充分利用CPU?

 如何理解开多线程可以充分利用CPU?

  <1>操作系统采用时间片轮转调度算法分配的时间片给每个进程中的线程

  <2>操作系统的时间片轮转调度算法分配的时间片 在别的进程中都没有准备好( 比如在访问网络)的时候,自己的主线程也在访问网络,导致这个时间片空闲浪费了,但是当此时这个进程中有多个子线程的时候,而且处于等待时机,这个本来空闲的将要浪费掉的时间片就会分配给这个子线程,起到充分利用CPU,提高任务执行效率的作用.
       实际上,CPU不可能得到100%的利用,肯定有浪费的,而开启多线程,就能够更充分地利用这些可能要浪费的时间片

 

 

 

 

 

如果你和我有共同爱好,我们可以加个好友一起交流!

 

 

 

 

c# – CPU未充分利用.由于阻塞I / O?

c# – CPU未充分利用.由于阻塞I / O?

我试图找到哪里是C#服务器应用程序的瓶颈,这个应用程序利用了cpu.我认为这可能是由于磁盘I / O性能不佳,与应用程序本身无关,但是我无法想出这个假设.

应用程序从本地MSMQ队列读取消息,对每个消息执行一些处理,并在处理消息后,将响应消息发送到另一个本地MSMQ队列.

我正在使用异步循环来读取队列中的消息,尽可能快地发出消息,并使用Task.Run调度它们进行处理,以启动每个消息的处理(而不是等待这个Task.Run ..只是附加一个连续只有错误才能记录错误).每个消息被并发处理,即在处理下一个消息之前不需要等待消息被完全处理.

在消息处理结束时,我使用MessageQueue的Send方法(以某种方式异步但不是真的因为在返回之前必须等待磁盘写入–see System.Messaging – why MessageQueue does not offer an asynchronous version of Send).

对于基准测试,我排队队列中的100K消息(100K消息总共大约100MB),然后启动该程序.在我的两台个人电脑(一台SSD HD,另一款采用i7 cpu quadcores -8逻辑处理器)上,我在程序生命周期内达到〜95%的cpu使用率(出列100K消息,处理它们和发送回复).消息可以尽可能快地出现,尽可能快地处理(这里涉及cpu),然后响应发送到不同本地队列的每个消息.

现在在运行非HT双核cpu的虚拟机上(不知道什么是底层磁盘,但在基准测试中似乎远低于矿山的性能),Perfmon可以看到平均磁盘秒/写在10-15毫秒VM,而在我的个人机器上是2ms的)当我运行相同的台式机时,我只能达到〜55%的cpu(当我在机器上运行相同的台式机而不发送响应消息到队列时,我达到〜90%的cpu ).

我真的不明白这里有什么问题.似乎很清楚,发送消息到队列是问题,并减慢了程序的全局处理(并且要处理的消息的出队),但是为什么会考虑我正在使用Task.Run来启动每个出队消息的处理并最终响应发送,我不会指望cpu未充分利用.除非一个线程发送消息,否则阻止其他线程在等待返回(磁盘写入)的同一个核心上运行,在这种情况下,考虑到等待时间远远高于我的个人计算机,这可能是有意义的,但是线程等待I / O不应阻止其他线程运行.

我真的想了解为什么我没有达到这台机器上至少95%的cpu使用率.我盲目地说这是由于磁盘I / O性能较差,但是我仍然不明白为什么会导致cpu利用率不足,因为我正在使用Task.Run同时运行处理.它也可能是与磁盘完全无关的一些系统问题,但考虑到MessageQueue.Send似乎是问题,并且该方法最终将消息写入内存映射文件磁盘,我看不到性能问题可能来自其他比磁盘.

当然这是一个系统性能问题,因为该程序可以最大限度地在我自己的计算机上使用cpu,但是我需要找到VM系统上的瓶颈,以及为什么它会影响我的应用程序的并发性/速度.

任何想法 ?

解决方法

为了检查光盘和/或cpu的利用率差,只有一个工具:Windows Performance Toolkit.有关如何使用它的示例,请参阅 here.
您应该从Windows 8.1 SDK(需要.NET 4.5.1)中获得最新的功能,它可以为您提供最多的功能,但Windows 8 SDK中的功能也很好.

您可以获得图表%cpu利用率和%光盘利用率.如果任一个在100%,另一个是低,那么你已经找到了瓶颈.由于它是一个系统范围的分析器,您可以检查msmq服务是否严重使用光盘,或者您或其他人(例如病毒扫描程序是常见问题).

你可以直接访问你的调用堆栈,并检查哪个进程和线程唤醒你的工作线程,这应该是全速运行的.然后,您可以跳转到准备好的线程并处理并检查它在做好线程之前做了什么.这样你就可以直接验证什么是阻碍它的时间.

没有更多的猜测.你真的可以看到系统正在做什么.

要分析进一步启用cpu使用精确度查看以下列:

> NewProcess
> NewThreadId
> NewThreadStack(框架标签)
> ReadyingProcess
> ReadyingThreadId
准备(我们)总和
等等(我们)总和
>等(我们)
> cpu占用率

然后在进程中向下钻取一个调用堆栈,以查看哪里高等待(我们)的时间确实发生在应该以全速运行的线程中.您可以深入到一个单一的事件,直到你不再进一步.然后,您将在Reading Process和ReadyingThreadId中看到值.转到该进程/线程(它可以是您自己的)并重复该过程,直到最终导致某些阻塞操作涉及到磁盘IO或睡眠或长时间运行的设备驱动程序调用(例如病毒扫描程序或vm驱动程序).

C++并发编程:如何利用多核CPU实现并发?

C++并发编程:如何利用多核CPU实现并发?

c++++ 并发编程通过创建线程、互斥锁和条件变量来充分利用多核 cpu 的优势。创建线程允许任务并行执行。互斥锁充当锁,确保共享数据不会被多个线程同时访问,从而避免数据损坏。条件变量用于通知线程特定条件已满足,并与互斥锁配合使用以防止线程继续执行直到条件满足。

C++并发编程:如何利用多核CPU实现并发?

C++ 并发编程:解锁多核 CPU

前言

现代 CPU 通常具有多个核心,通过充分利用这些核心,我们可以在并行执行任务时显着提高代码效率。C++ 提供了各种并发编程工具,使程序员能够轻松创建可以同时执行多个任务的应用程序。

立即学习“C++免费学习笔记(深入)”;

点击下载“修复打印机驱动工具”;

创建线程

创建线程是表示并发的基本构造块。在 C++ 中,可以使用 std::thread 类创建新线程。它接受一个可调用对象作为参数,该对象指定在单独的线程中执行的任务。

#include <iostream>
#include <thread>

void hello_world() {
  std::cout << "Hello, world!" << std::endl;
}

int main() {
  std::thread thread1(hello_world);
  thread1.join();

  return 0;
}
登录后复制

在上面的代码中,hello_world() 函数是一个可调用对象,它只需向控制台打印一条消息。std::thread 构造函数创建一个新线程并执行可调用对象。thread1.join() 阻塞主线程,直到新线程完成。

互斥锁

线程并发访问共享数据时,互斥锁非常重要。它们充当锁,防止多个线程同时访问关键部分,从而避免数据损坏。在 C++ 中,可以使用 std::mutex 类创建互斥锁。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;  // 全局互斥锁

void increment(int& counter) {
  std::lock_guard<std::mutex> lock(m);  // 获取互斥锁
  ++counter;
}

int main() {
  int counter = 0;

  std::thread thread1(increment, std::ref(counter));
  std::thread thread2(increment, std::ref(counter));

  thread1.join();
  thread2.join();

  std::cout << "Final counter value: " << counter << std::endl;

  return 0;
}
登录后复制

在这个示例中,increment() 函数对共享变量 counter 进行递增。我们使用 std::lock_guard 来获取互斥锁,确保只有一个线程可以同时执行关键部分。这种机制确保两个线程不会同时递增 counter,从而避免数据竞争。

条件变量

条件变量用于通知线程特定条件已满足。它们与互斥锁一起使用,以确保线程在满足条件之前不会继续执行。在 C++ 中,可以使用 std::condition_variable 类创建条件变量。

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>

std::mutex m;  // 全局互斥锁
std::condition_variable cv;  // 全局条件变量
bool ready = false;  // 共享布尔标志

void producer() {
  std::lock_guard<std::mutex> lock(m);  // 获取互斥锁
  ready = true;                       // 设置共享标志为 true
  cv.notify_one();                   // 通知一个等待的线程
}

void consumer() {
  std::unique_lock<std::mutex> lock(m);  // 获取互斥锁(并锁定它)
  while (!ready)                        // 等待共享标志为 true
    cv.wait(lock);                     // 释放互斥锁并等待
}

int main() {
  std::thread producer_thread(producer);
  std::thread consumer_thread(consumer);

  producer_thread.join();
  consumer_thread.join();

  return 0;
}
登录后复制

在此示例中,我们使用条件变量来协调生产者和消费者线程之间的交互。producer() 函数设置共享标志 ready 为 true 并通知消费者线程。consumer() 函数通过等待条件变量来等待共享标志为 true,然后继续执行。

以上就是C++并发编程:如何利用多核CPU实现并发?的详细内容,更多请关注php中文网其它相关文章!

Golang能否充分利用多核处理器的优势?

Golang能否充分利用多核处理器的优势?

golang能否充分利用多核处理器的优势?

Golang能否充分利用多核处理器的优势?

随着计算机技术的飞速发展,多核处理器已经成为现代计算机的标配。如何充分利用多核处理器的优势,让程序能够更高效地运行,一直是程序员们关注的焦点。在这个问题上,Golang这门编程语言表现如何呢?今天我们将探讨一下Golang在利用多核处理器上的优势,并结合具体的代码示例进行分析。

首先,让我们来了解一下Golang的特点。Golang是一门由Google开发的编程语言,具有内置并发支持的特性。Golang通过goroutine和channel来实现并发编程,这为利用多核处理器提供了很好的支持。goroutine是一种轻量级的线程,在Golang中可以很容易地创建和管理,而channel则用于在不同goroutine之间进行通信和数据交换。

接下来,我们来看一个具体的代码示例,展示Golang如何利用多核处理器的优势。下面的示例代码通过并发的方式计算一组数字的总和,从而展示了如何利用goroutine和channel来实现并行计算:

立即学习“go语言免费学习笔记(深入)”;

package main

import (
    "fmt"
)

func sum(numbers []int, resultChannel chan int) {
    sum := 0
    for _, num := range numbers {
        sum += num
    }
    resultChannel <- sum
}

func main() {
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    numWorkers := 4
    resultChannel := make(chan int)

    chunkSize := len(numbers) / numWorkers
    for i := 0; i < numWorkers; i++ {
        start := i * chunkSize
        end := start + chunkSize
        go sum(numbers[start:end], resultChannel)
    }

    total := 0
    for i := 0; i < numWorkers; i++ {
        total += <-resultChannel
    }

    fmt.Println("Total sum:", total)
}
登录后复制

在这段代码中,我们首先定义了一个sum函数,用于计算一组数字的总和,并通过resultChannel将计算结果传递回主线程。然后在main函数中,我们将数字拆分成多个chunk,并通过并发的方式启动了多个goroutine来计算每个chunk的总和。最后,主线程等待所有goroutine计算完成后,将各个chunk的总和相加得到最终的结果。

通过这种方式,我们可以充分利用多核处理器的优势,将计算任务合理地分配给不同的核心进行并行计算,从而提高程序的运行效率。这也展示了Golang在并发编程方面的优秀表现,使得开发者能够更轻松地编写高效的并行程序。

总的来说,Golang能够很好地利用多核处理器的优势,通过goroutine和channel的并发模型,使得程序能够更高效地运行。当然,在实际开发中,还有很多其他技术和工具可以帮助我们更好地利用多核处理器,但Golang作为一门支持并发编程的语言,为我们提供了很好的支持和帮助。希望通过这篇文章能够帮助读者更好地理解Golang在利用多核处理器上的优势。

以上就是Golang能否充分利用多核处理器的优势?的详细内容,更多请关注php中文网其它相关文章!

关于怎样用 NodeJS 充分利用多核 CPU 的资源node如何利用多核的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于3.如何理解开多线程可以充分利用CPU?、c# – CPU未充分利用.由于阻塞I / O?、C++并发编程:如何利用多核CPU实现并发?、Golang能否充分利用多核处理器的优势?的相关知识,请在本站寻找。

本文标签:

上一篇webview Java与JS互调(webview与js交互)

下一篇如何调试Node.js应用程序? - How do I debug Node.js applications?(怎样调试node.js程序)