node

node单线程,没有并发,但是可以利用cluster进行多cpu的利用。cluster是基于child_process的封装,帮你做了创建子进程,负载均衡,IPC的封装。

const cluster = require('cluster');
const http = require('http'); if (cluster.isMaster) { let numReqs = 0;
setInterval(() => {
console.log(`numReqs = ${numReqs}`);
}, 1000); function messageHandler(msg) {
if (msg.cmd && msg.cmd === 'notifyRequest') {
numReqs += 1;
}
} const numCPUs = require('os').cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
} for (const id in cluster.workers) {
cluster.workers[id].on('message', messageHandler);
} } else { // Worker processes have a http server.
http.Server((req, res) => {
res.writeHead(200);
res.end('hello world\n'); process.send({ cmd: 'notifyRequest' });
}).listen(8000);
}

我们通过cluster.fork()来创造几个子进程,让子进程来替我们工作。在fork的时候会传一个参数到子进程,cluster.isMaster就是根据有没有这个参数判断的。

如果是子进程就起一个server。

每个子进程都会绑定到8000端口,这不会引起端口占用吗?

答案是不会,因为listen并不会真的监听到8000端口,它会通过IPC把子进程的消息传到主进程,主进程会创建服务器,然后调用子进程的回调。

在子进程的回调中:子进程会根据主进程是否返回handle句柄来执行下一步的操作,如果没有handle句柄,说明在负载均衡的策略没有选中本进程。那么就自己造一个handle对象返回。

那自己造个对象怎么返回请求呢?

请求到主进程,主进程会分发请求,处理到该请求的子进程会通过IPC与主进程通信,这样就完成了一个请求的响应。

通过cluster完成单机器的负载均衡,那么多机器呢?还是得用nginx。

node & pm2

pm2 是node的进程管理工具,它封装了cluster,可以通过命令行来创建多个进程来处理。

写个config文件:

app.json

{
"name" : "app",
"script" : "src/main.js",
"watch" : true,
"merge_logs" : true,
"instances" : "max", // 使用cluster
"error_file" : "./log/error.log",
"out_file" : "./log/asccess.log",
"pid_file" : "./log/pid.pid",
"cwd" : "./",
"max_restarts" : 10,
"min_uptime": "10s",
"env": {
"NODE_ENV": "development",
"BABEL_ENV": "node"
},
"env_prod" : {
"NODE_ENV": "production"
}
}
pm2 start app.json

也可以不写配置文件直接写pm2 start -i 4 --name server index.js

开启4个instance。

通过参数开启多个子进程,而不需要修改我们的业务代码。

go

go也是非阻塞io,Golang默认所有的任务都在一个cpu核里,如果想使用多核来跑goroutine的任务,需要配置runtime.GOMAXPROCS。

自从Go 1.5开始, Go的GOMAXPROCS默认值已经设置为 CPU的核数,我们不用手动设置这个参数。

我们先说说go的并发。

go本身就可以通过go关键字来进行并发操作。go关键字创建的并发单元在go中叫goroutine。

比如:

 package main

  import (
"fmt"
"time",
// "runtime"
)
func main() {
go func(){
fmt.Println("123")
}() go func(){
fmt.Println("456")
}()
// runtime.Gosched()
fmt.Println("789")
time.Sleep(time.Second)
}

会打印789 ,123,456,或者 780,456,123。

在主线程开始就通过go字段开启了2个goroutine,两个goroutine的执行顺序不确定。

如果当前goroutine发生阻塞,它就会让出CPU给其他goroutine。

如果当前goroutine不发生阻塞,一直在执行,那么什么时候执行其他goroutine就看go调度器的处理了。

不过go提供runtime.Gosched()来达到让出CPU资源效果的函数,当然不是不执行,会在之后的某个时间段执行。如果把注释去掉,789就会最后执行。

单核的时候其实goroutine并不是真的“并行”,goroutine都在一个线程里,它们之间通过不停的让出时间片轮流运行,达到类似并行的效果。

如果我在123,或者456之前加 time.Sleep(time.Second)。那么CPU的资源又会转让回主进程。

当一个goroutine发生阻塞,Go会自动地把与该goroutine处于同一系统线程的其他goroutines转移到另一个系统线程上去,以使这些goroutines不阻塞,主线程返回的时候goroutines又进入runqueue

下面这段代码:


import (
"fmt"
"runtime"
) var quit chan int = make(chan int) func loop() {
for i := 0; i < 100; i++ { //为了观察,跑多些
fmt.Printf("%d ", i)
}
quit <- 0
} func main() {
runtime.GOMAXPROCS(1) go loop()
go loop() for i := 0; i < 2; i++ {
<-quit
}
}

会打印什么呢?

runtime.GOMAXPROCS(2)改成双核cpu,又会打印什么呢?

我们能看到,双核cpu的时候,goroutine会真正的并发执行而不是并行。他们会抢占式的执行。

参考https://studygolang.com/articles/1661

python

python是有多线程的,但是python有gil影响了他的多cpu利用。

GIL是CPython中特有的全局解释器锁

这把锁在解释器进程中是全局有效的,它主要锁定Python线程的CPU执行资源。

想要执行多核的进程需要满足2个条件

  1. 被操作系统调度出来【操作系统允许它占用CPU】
  2. 获取到GIL【CPython解释器允许它执行指令】

python在单核cpu上执行没有问题,这个线程总能获得gil,但是在多核的时候,线程会出现竞争,GIL只能同时被一个线程申请到,没申请到的就会被阻塞,就会一直处于闲置状态。

到线程切换时间然后睡眠,被唤醒之后获取gil又失败,恶性循环。

特别是计算型线程,会一直持有gil。

GIL 可以被 C 扩展释放,Python 标准库会在每次 I/O 阻塞结束后释放 GIL,因此 GIL 不会对 I/O 服务器产生很大的性能影响。因此你可以 fork 进程或者创建多线程来创建网络服务器处理异步 I/O,GIL 在这种情况下并没有影响。

解决方案:

  1. 使用python3.4或更高版本(对GIL机制进行了优化)
  2. 使用多进程替换多线程(多进程之间没有GIL,但是进程本身的资源消耗较多)
  3. 指定cpu运行线程(使用affinity模块)
  4. 全IO密集型任务时使用多线程
  5. 协程 (gevent模块)

Python 3.2开始使用新的GIL。新的GIL实现中用一个固定的超时时间来指示当前的线程放弃全局锁。在当前线程保持这个锁,且其他线程请求这个锁时,当前线程就会在5毫秒后被强制释放该锁。

总结

node是没有多线程的利用的,只能用多进程来利用多核cpu,python因为gil的问题,也没法完全利用多线程,但是有一些神奇的方案可以利用比如指定cpu运行。

go的实现是比较好的,毕竟是后来的语言,可以多核跑协程,来利用cpu

go/node/python 多进程与多核cpu的更多相关文章

  1. python多线程不能利用多核cpu,但有时候多线程确实比单线程快。

    python 为什么不能利用多核 CPU  GIL 其实是因为在 python中有一个 GIL( Global Interpreter Lock),中文为:全局解释器锁.  1.最开始时候设计GIL是 ...

  2. python 导入numpy 导致多进程绑定同一个CPU问题解决方法

    python 如果有导入numpy模块的import语句,会导致默认将多进程程序的每个进程都绑定到同一个CPU core上, 失去了多进程在多核CPU上的性能优越性,这和CPU affinity(CP ...

  3. 为什么在Python里推荐使用多进程而不是多线程?(为什么python多线程无法增加CPU使用率?)

    最近在看Python的多线程,经常我们会听到老手说:“Python下多线程是鸡肋,推荐使用多进程!”,但是为什么这么说呢? 要知其然,更要知其所以然.所以有了下面的深入研究: 首先强调背景:     ...

  4. python GIL 全局锁,多核cpu下的多线程性能究竟如何?

    python GIL 全局锁,多核cpu下的多线程性能究竟如何?GIL全称Global Interpreter Lock GIL是什么? 首先需要明确的一点是GIL并不是Python的特性,它是在实现 ...

  5. 多核CPU上python多线程并行的一个假象

    GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题.运行下面这段 python 程序,CPU 占用率是多少? # 请勿在工作 ...

  6. python多线程为什么不能利用多核cpu

    GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题.运行下面这段 python 程序,CPU 占用率是多少? # 请勿在工作 ...

  7. 浅谈多核CPU、多线程、多进程

    1.CPU发展趋势 核心数目依旧会越来越多,依据摩尔定律,由于单个核心性能提升有着严重的瓶颈问题,普通的桌面PC有望在2017年末2018年初达到24核心(或者16核32线程),我们如何来面对这突如其 ...

  8. python学习笔记(二十九)为什么python的多线程不能利用多核CPU

    问题:为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快原因:因为GIL,python只有一个GIL,运行python时,就要拿到这个锁才能执行 ...

  9. Python基础补充(二) 多核CPU上python多线程并行的一个假象【转】

    在python上开启多个线程,由于GIL的存在,每个单独线程都会在竞争到GIL后才运行,这样就干预OS内部的进程(线程)调度,结果在多核CPU上: python的多线程实际是串行执行的,并不会同一时间 ...

随机推荐

  1. angualr跨域访问配置

    浏览器对于javascript的同源策略的限制,例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了: 简单的解释就是相同域名,端口相同,协议 ...

  2. .NET CORE学习笔记系列(6)——KestrelServer

    原文:http://www.cnblogs.com/artech/p/KestrelServer.html 跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了 ...

  3. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  4. Flink流处理的时间窗口

    Flink流处理的时间窗口 对于流处理系统来说,流入的消息是无限的,所以对于聚合或是连接等操作,流处理系统需要对流入的消息进行分段,然后基于每一段数据进行聚合或是连接等操作. 消息的分段即称为窗口,流 ...

  5. tmpfs使用探讨

    一. 什么是tmpfs? tmpfs是一种基于内存的文件系统,它和虚拟磁盘ramdisk比较类似,但不完全相同,和ramdisk一样,tmpfs可以使用RAM,但它也可以使用swap分区来存储. 而且 ...

  6. Linux运维基础

    一.服务器硬件 二.Linux的发展史 三.Linux的系统安装和配置 四.Xshell的安装和优化 五.远程连接排错 六.Linux命令初识 七.Linux系统初识与优化 八.Linux目录结构 九 ...

  7. Django-CRM项目学习(六)-rbac模块(权限组件)

    1.rbac权限组件 1.1 模板分析(五表结构) 1.2 模板构建 人物和角色进行多对多绑定,角色与权限进行多对多绑定.其中人物和角色的多对多绑定的操作可以避免相同的人物多重权限的操作. 1.3 数 ...

  8. windows下搭建nginx+php+laravel开发环境(转)

    1.前言 windows下大多我们都是下载使用集成环境,但是本地已经存在一个集成环境,但不适合项目的需求.因此准备再自己搭建一个环境. 2.准备 工具: 1) 下载 nginx1.14.0(版本根据自 ...

  9. IDEA+API && SPI

    JAVA中API和SPI的区别:https://blog.csdn.net/quanaianzj/article/details/82500019

  10. 采用ADM2483磁隔离器让RS485接口更简单更安全

    采用ADM2483磁隔离器让RS485接口更简单更安全 摘要:本文介绍RS485的特点及应用,指出了普通RS485接口易损坏的问题,针对存在的问题介绍了以ADM2483为核心的磁隔离解决方案. 关键词 ...