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 mainimport ("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

转载于:https://www.cnblogs.com/dh-dh/p/9174294.html

go/node/python 多进程与多核cpu相关推荐

  1. python 多进程 多核_go/node/python 多进程与多核cpu

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

  2. Python怎么利用多核cpu

    <!--一个博主专栏付费入口结束--><link rel="stylesheet" href="https://csdnimg.cn/release/p ...

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

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

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

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

  5. Python 多进程向同一个文件写数据

    1.遇到的问题: 之前,因为考虑到Python多进程可以充分利用CPU核数,提高程序的效率,所以就使用多进程写文件.但是向同一个文件写入数据的时候,由于多进程是并发进行,操作系统中会不清楚到底要写入哪 ...

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

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

  7. 多核CPU上python多线程并行的一个假象(转)

    转自:http://www.cnblogs.com/skying555/p/6527189.html GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么 ...

  8. python多核cpu_Python中的多核CPU共享数据之协程详解

    一 : 科普一分钟 尽管进程间是独立存在的,不能相互访问彼此的数据,但是在python中却存在进程间的通信方法,来帮助我们可以利用多核CPU也能共享数据. 对于多线程其实也是存在一些缺点的,不是任何场 ...

  9. python提高运行效率_提高CPU密集型任务执行效率——Python多进程介绍,内附实例代码...

    multiprocessing模块介绍 Python中多线程无法利用多核优势,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程,Python提供了multiprocessi ...

最新文章

  1. 如何在centos7下tomcat中安装https
  2. MySQL 数据库常用命令
  3. python读取csv某一列存入数组_python 读取.csv文件数据到数组(矩阵)的实例讲解
  4. php拒绝服务,CVE-2015-7803
  5. codeforces gym-101673 Twenty Four, Again 24点,枚举表达式树过题
  6. ftp无法连接虚拟机_一步步编写操作系统4 安装x86虚拟机 bochs
  7. 基于xml技术的操作
  8. 分布式事务的理解和解决方法
  9. 计算机图形学E6——倒水问题emm和OpenGL没啥关系
  10. 【Kafka】Kafka BrokerEndPointNotAvailableException: End point with security protocol PLAINTEXT not
  11. dwz java_dwz.cn接口java客户端实现
  12. 网络编程 之osi七层协议
  13. 【分享用于学习C++图像处理的代码示例】框架
  14. UE4使用openCV库启动编辑器报错
  15. 删除文件夹时,报错“错误ox80070091:目录不是空的”,该如何解决?
  16. Simultaneously Localize, Segment and Rank the Camouflaged Objects阅读笔记
  17. 美术 2.1 DCC工具链与引擎工具链
  18. R语言学习之数据分析实战(一)
  19. java 多线程(三)
  20. CIO免费IT预算计划模板

热门文章

  1. python_day3作业
  2. windows server 2003 AD
  3. 通过java反射机制获取该类的所有属性类型、值。
  4. ASP.NET之.NET FrameWork框架
  5. 【原创】leetCodeOj ---Convert Sorted List to Binary Search Tree 解题报告
  6. Zend Framework数据库操作(1)
  7. python将第一列替换_python-通过将另一列与第二个DataFrame进行比较来替换一列中的值...
  8. hdu4115 2sat 石头剪刀布
  9. 【Linux 内核 内存管理】Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
  10. 【Groovy】Groovy 扩展方法 ( 实例扩展方法配置 | 扩展方法示例 | 编译实例扩展类 | 打包实例扩展类字节码到 jar 包中 | 测试使用 Thread 实例扩展方法 )