Node 事件循环及多线程
浏览器事件循环
JS 为什么是单线程的
浏览器 JS 的作用是操作 DOM,这决定了它只能是单线程的,否则会带来很多复杂的问题
- 比如:假定 JavaScript 同时又两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
浏览器是多线程
浏览器基于 EventQueue 事件队列、EventLoop 事件循环两大机制,构建出 “异步编程的效果” -> 单线程异步操作
- GUI 渲染线程
- JS 引擎线程【渲染解析 JS 的】
- DOM/定时器监听等线程
- HTTP 网络线程
浏览器中的 Event Loop
- 主线程从任务队列中读取事件,这个过程是循环不断的,这种整个运行机制又称为
Event Loop
(事件循环) - 执行栈在执行完 同步任务 后,查看 执行栈 是否为空,如果 执行栈 为空,就回去检查 微任务 队列是否为空,如果为空的话,就会执行 宏任务,否则就一次性执行完所有 微任务
事件队列分为同步任务(synchronous)和异步任务(asynchronous)
- 所有同步任务都在主线程上执行,形成了一个执行栈(execution content stack)
- 主线程之外,还存在一个 “任务队列” (task queue),只要异步任务有了运行结果,就在 “任务队列” 之中放置一个事件
- 一旦 “执行栈” 中的所有同步任务执行完毕,系统就会读取 “任务队列”,看看里面有哪些事件,哪些对应的异步任务,于是等任务结束状态,进入执行栈,开始执行
- 主线程不断重复上面的第三步
除了广义的同步任务和异步任务,异步任务可以细分为宏任务(macrotask)和微任务(microtask)
-
宏任务
UI rendering 是浏览器的宏任务
浏览器 | Node | |
---|---|---|
I/O | ✔️ | ✔️ |
setTimeout | ✔️ | ✔️ |
setInterval | ✔️ | ✔️ |
setImmediate | ❌ | ✔️ |
requestAnimationFrame | ✔️ | ❌ |
- 微任务
浏览器 | Node | |
---|---|---|
process.nextTick | ❌ | ✔️ |
MutationObserver | ✔️ | ❌ |
Promise.then catch finally | ✔️ | ✔️ |
- 练习:
setTimeout(() => {console.log('setTimeout')
}, 0)Promise.resolve().then(() => {console.log('promise1')Promise.resolve().then(() => {console.log('promise2')})
})
// promise1 promise2 setTimeout/* ---------- */setTimeout(() => {Promise.resolve().then(() => {console.log('promise')})
}, 0)Promise.resolve().then(() => {setTimeout(() => {console.log('setTimeout')}, 0)
})
console.log('main')
// main promise setTimeout
Node.js 事件循环
Node 的 Event Loop 是基于 libuv
实现的,libuv
使用异步、事件驱动的编程方法,核心是提供 I/O
的事件循环和异步回调
事件循环六个阶段
一次弄懂Event Loop(彻底解决此类面试问题)
The Node.js Event Loop
Node 的 Event Loop 是基于 libuv
实现的,libuv
使用异步、事件驱动的编程方法,核心是提供 I/O
的事件循环和异步回调
当 Node.js 启动时会初始化 Event Loop,每一个 Event Loop 都会包含如下六个循环阶段:
阶段概览
-
timers(定时器):此阶段执行那些由
setTimeout()
和setInterval()
调度的回调函数 -
pending callbacks:执行 I/O 回调,此阶段执行几乎所有的回调函数,除了 close callbacks(关闭回调) 和那些由 timers 与
setImmediate()
调度的回调setImmediate() ≈ setTimeout(cb, 0)
-
idle(空转),prepare:此阶段只在内部使用
-
poll(轮询):检索新的 I/O 事件,在恰当的时候 Node 会阻塞这个阶段
-
check(检查):
setImmediate()
设置的回调会在这个阶段被调用 -
close callbacks(关闭事件的回调):诸如:
http.server.on('close', [fn])
、socket,on('close', [fn])
,此类的回调会在此阶段被调用
poll 阶段
如果 Event Loop 进入了 poll 阶段,且代码未设定 timer
,将会发生下面情况:
- 如果
poll
队列不为空,则 Event Loop 将 同步执行callback
队列,直至队列为空或者达到系统上限 - 如果
poll
队列为空,将会发生下面情况:- 如果有
setImmediate()
回调需要执行, Event Loop 会立即停止执行 poll 阶段并执行 check 阶段,然后执行回调 - 如果没有
setImmediate()
回调需要执行,Event Loop 将阻塞在 poll 阶段,等待callback
被添加到任务队列中,然后执行
- 如果有
如果 Event Loop 进入了 poll 阶段,且代码设定了 timer
:
- 如果
poll
队列为空,则 Event Loop 将检查timer
是否超时,如果有的话会回到 timers 阶段执行回调
不同版本 Node
- 浏览器只要执行了一个宏任务就会执行微任务队列
- Node 10(11以下) 中只有全部执行了 timers 阶段队列的全部任务才执行微任务队列
- Node 11 在 timers 阶段的
setTimeout()
、setInterval()
和在 check 阶段的setImmediate()
修改为一旦执行一个阶段里的一个任务就会执行微任务队列
fs 和 setTimeout 的关系
- 执行
setTimeout(fn, 10)
,会立即执行 Node 六个阶段,当前时间为 0ms, timers 阶段没有任何callback
加入,跳过 - 执行 pending callbacks 阶段,执行定时器或
setImmediate
以外的回调,没有跳过 - 执行 poll 阶段,
poll
队列为空且没有setImmediate()
,会阻塞等待 2ms,等待fs.readfile
读取文件完毕执行其回调,会调阻塞代码 20ms - 此时时间为 22ms,
poll
队列为空且有设定的timer
,因为setTimeout
的回调执行 10ms,此时时间已经达到,事件循环会进入 timers 阶段,执行setTimeout(fn, 10)
const fs = require('fs')
const path = require('path')function someAsyncOperation(callback) {// 花费2msfs.readFile(path.resolve(__dirname, '/read.txt'), callback)
}const timeoutScheduled = Date.now()
let fileReadTime = 0setTimeout(() => {const delay = Date.now() - timeoutScheduledconsole.log(`setTimeout: ${delay} ms have passed since I was scheduled`)console.log(`fileReaderTime ${fileReadTime - timeoutScheduled}`)
}, 10)someAsyncOperation(() => {fileReadTime = Date.now()while (Date.now() - fileReadTime < 20) {} // 卡住20ms
})
/*
setTimeout: 22 ms have passed since I was scheduled
fileReaderTime 2
*/
稍微做下改变,假设文件读取花费了 9ms,定时器只花了 5ms
- 执行
setTimeout(fn, 5)
,当前时间为 0ms, timers 阶段没有任何callback
加入,跳过 - 执行 pending callbacks 阶段,执行定时器或
setImmediate
以外的回调,没有跳过 - 执行 poll 阶段,
poll
队列为空且没有setImmediate()
,会阻塞等待 5ms,当前时间为 5ms,此时poll
队列为空且设定了timer
,事件循环会进入 timers 阶段,执行setTimeout(fn, 5)
- 重新执行阶段,走到 poll 阶段,继续阻塞,当前时间等待到 9ms,执行
fs.readFile
const fs = require('fs')
const path = require('path')function someAsyncOperation(callback) {// 花费9msfs.readFile(path.resolve(__dirname, '/read.txt'), callback)
}const timeoutScheduled = Date.now()
let fileReadTime = 0setTimeout(() => {const delay = Date.now() - timeoutScheduledconsole.log(`setTimeout: ${delay} ms have passed since I was scheduled`)console.log(`fileReaderTime ${fileReadTime - timeoutScheduled}`)
}, 5)someAsyncOperation(() => {fileReadTime = Date.now()while (Date.now() - fileReadTime < 20) {} // 卡住20ms
})
/*
setTimeout: 5 ms have passed since I was scheduled
fileReaderTime 9
*/
setTimeout 和 setImmediate
在 Node.js 中,
setTimeout(fn, 0) === setTimeout(fn, 1)
在浏览器里,
setTimeout(fn, 0) === setTimeout(fn, 4)
setTimeout 和 setImmediate 执行顺序不确定
- 因为事件循环启动也是需要时间的,可能执行 poll 阶段已经超过了 1ms,此时
setTimeout
会先执行,反之setImmediate
先执行
setImmediate(() => {console.log('setImmediate')
})setTimeout(() => {console.log('setTimeout')
}, 0)
// 一次 setImmediate setTimeout
// 一次 setTimeout setImmediate
setTimeout 和 setImmediate 执行顺序是确定的
-
一开始
poll
队列为空,没有设定setImmediate
,代码会进行阻塞,执行fs.readFile
,2ms 后读取文件完毕,执行其回调 -
poll
队列为空,且设定了setImmediate
,结束 poll 阶段进入 check 阶段,check 阶段会执行setImmediate
,此时会执行setImmediate
即使
setTimeout
和setImmediate
替换位置也是setImmediate
先执行
const fs = require('fs')
const path = require('path')fs.readFile(path.resolve(__dirname, '/read.txt'), () => {setImmediate(() => {console.log('setImmediate')})setTimeout(() => {console.log('setTimeout')}, 0)
})
// setImmediate setTimeout
process.nextTick
process.nextTick() 不在 Event Loop 的任何阶段执行,而是在各个阶段切换的中间执行,即从一个阶段切换到下个阶段前执行
- 执行
fs.readFile
,首先setTimeout
、setImmediate
放进 I/O 里,此时有setImmediate()
回调需要执行,事件循环立即结束 poll 阶段并执行 check 阶段,执行nextTick()
,然后执行回调 - check 阶段之后会到第二个事件循环的 timer 阶段,执行
nextTick()
,再执行setTimeout
回调
const fs = require('fs')
const path = require('path')fs.readFile(path.resolve(__dirname, '/read.txt'), () => {setTimeout(() => {console.log('setTimeout')}, 0)setImmediate(() => {console.log('setImmediate')process.nextTick(() => {console.log('nextTick3')})})process.nextTick(() => {console.log('nextTick1')})process.nextTick(() => {console.log('nextTick2')})
})
nextTick 应用场景
-
在多个事件里交叉执行 CPU 运算密集型的任务:
在这种模式下,我们不需要递归的调用
compute()
,我们只需要在事件循环中使用process.nextTick()
定义compute()
在下一个时间点执行即可。在这个过程中,如果有新的 http 请求进来,事件循环机制会先处理新的请求,然后再调用computed()
。反之,如果你把compute()
放在一个递归调用里,那系统就会一直阻塞在computed()
里,无法处理新的 http 请求了const http = require('http')function compute() {process.nextTick(compute) }http.createServer((req, res) => {res.writeHead(200, { 'Content-Type': 'text/plain' })res.end('hello world')}).listen(5000, '127.0.0.1')compute()
-
保持回调函数异步执行的原则
当你给一个函数定义一个回调函数时,你要确保这个回调是被异步执行的。下面这个例子中的回调函数违反了这个原则:
function asyncFake(data, callback) {if (data === 'foo') callback(true)else callback(false) } asyncFake('bar', result => {})const client = net.connect(8124, () => {console.log('client connected')client.write('hello world\r\n') })
如果是因为某种原因,
net.connect()
变成同步执行的了,回调函数就会被立即执行,因此回调函数写到客户端的变量就永远不会被初始化了这种情况下我们就可以使用
process.nextTick()
把上面asyncFake()
改成异步执行的:function asyncReal(data, callback) {process.nextTick(() => {callback(data === 'foo')}) }
-
用在事件触发过程中
EventEmitter 有 2 个比较核心的方法,on 和 emit。node 自带发布/订阅模式
const EventEmitter = require('events').EventEmitterclass App extends EventEmitter {}const app = new App() app.on('start', () => {console.log('start') }) app.emit('start') console.log('111') // emit是同步的方法 /* start 111 */
const EventEmitter = require('events').EventEmitterfunction StreamLibrary() {const self = thisprocess.nextTick(() => {self.emit('start')}) } StreamLibrary.prototype.__proto__ = EventEmitter.prototypeconst stream = new StreamLibrary() // 保证订阅在发布之前 stream.on('start', () => {console.log('Reading has started') })
Node 多线程
多进程和多线程
为什么需要多进程
- Node.js 单线程,在处理 http 请求的时候一个错误都会导致整个进程的退出,这是灾难级的
线程和进程
- 进程是资源分配的最小单位,线程是 CPU 调度的最小单位
- “进程” —— 资源分配的最小单位
- “线程” —— 程序执行的最小单位
线程是进程的一个执行流,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程由几个线程组成,线程与同属一个进程的其它线程共享进程拥有的全部资源(一个进程下的线程可以去通信的、共享资源)
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径,线程有自己的堆栈和局部变量,但是线程没有单独的地址空间,一个线程死掉就等于整个进程死掉
举例:谷歌浏览器
- 进程:一个 Tab 页就是一个进程
- 线程:一个 Tab 页又有多个线程组成、渲染线程、JS 执行线程、垃圾回收、service worker 等等
举例:Node 服务
- ab 是 apache 自带的压力测试工具
ab -n1000 -c20 '192.168.31.25:8000/'
- 进程:监听某一个端口的 http 服务
- 线程:http 服务由多个线程组成,比如:
- 主线程:获取代码、编译执行
- 编译进程:主线程执行的时候,可以优化代码
- Profiler 线程:记录哪些方法耗时,为优化提供支持
- 其他线程:用于垃圾回收清理工作,因为是多个线程,所以可以并行清除
如何选选择多进程还是多线程
- 多进程还是多线程一般是结合起来使用,千万不要陷入非此即彼的误区
对比维度 | 多进程 | 多线程 | 总结 |
---|---|---|---|
数据共享、同步 | 数据共享复杂,需要用IPC:数据是分开的,同步简单 | 因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂 | 各有优势 |
内存、CPU | 占用内存多,切换复杂,CPU利用率低 | 占用内存少,切换简单,CPU利用率高 | 线程占优 |
创建销毁、切换 | 创建销毁、切换复杂,速度慢 | 创建销毁、切换简单,速度很快 | 线程占优 |
编程、调试 | 编程简单、调试简单 | 编程复杂、调试复杂 | 进程占优 |
可靠性 | 进程间不会互相影响 | 一个线程挂掉会导致整个进程挂掉 | 进程占优 |
分布式 | 适应于多核、多机分布式:如果一台机器不够,扩展到多台机器比较简单 | 适应于多核分布式 | 进程占优 |
-
需要频繁创建销毁的优先使用线程
这种原则最常见的应用就是 Web 服务器了,来一个连接建立一个线程,断了就销毁线程,要是用进程,创建和销毁的代价是很难承受的
-
需要进行大量计算的优先使用线程
所谓大量计算,当然就是耗费很多 CPU,切换频繁了,这种情况下线程是最合适的
这种原则最常见的是图像处理、算法处理
-
强相关的处理使用线程,弱相关的处理使用进程
JS 和 DOM 强相关
浏览器两个窗口弱相关
一般的 Server 需要完成如下任务:消息收发、消息处理。“消息收发” 和 “消息处理” 就是弱相关任务,而 “消息处理” 里面可能又分为 “消息解码”、“业务处理”,这两个任务相对于来说相关性就要强多了,因此 “消息收发” 和 “消息处理” 可以分进程设计,“消息解码”、“业务处理” 可以分线程设计
-
可能要扩展到多机分布的用进程,多核分布用线程
-
都满足需求的情况下,用你最熟悉、最拿手的方式
总结:线程快而进程可靠性高
cluster
理解Node.js中的"多线程"
Node.js 真·多线程 Worker Threads 初探
Node API cluster 集群
Worker Threads
特性是在2018年6月20日的 v10.5.0 版本引入的
cluster 是 Node 进行多线程的模块
CPU 数量查询
- 我的电脑 —— 管理 —— 设备管理器 —— 处理器
-
任务管理器 —— CPU —— 逻辑处理器
这里可以看到我的电脑有 4 个内核 8 个逻辑处理器,有多少个逻辑处理器,就可以开多少个线程
cluster 基本使用
cluster 基本原理:主线程去 fork 子线程,然后管理它们
const cluster = require('cluster') // nodejs内置模块
const http = require('http')
const cpuNum = require('os').cpus().lengthconst port = 8000if (cluster.isMaster) {// 如果是主线程for (let i = 0; i < cpuNum; i++) {cluster.fork() // 开启子进程}
} else {// 子线程走这个http.createServer((req, res) => {res.writeHead(200)res.end('hello world\r\n')}).listen(port, () => {console.log(`running at: http://localhost:${port}/`)})
}
多进程和单进程性能对比
- 多进程的性能要明显好于单进程
安装 Apache
- 安装 Apache 可以参考这篇文章:Windows 10 安装Apache
- 安装问题可能出现的问题:通常每个套接字地址(协议/网络地址/端口)只允许使用一次::443
- CMD 中使用
netstat -a -o
查看哪些端口被占用
ab 是 apache 自带的压力测试工具,Mac 原生自带,无需安装
ab -n1000 -c50 127.0.0.1:8000/
-n
请求数-c
并发数
Node 调试方法
- 可以手动选择运行和调试中的
Launch Program
- 也可以在
.vscode
文件下面配置launch.json
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"type": "node","request": "launch","name": "Launch Program","program": "${workspaceFolder}\\你运行的JS文件"}]
}
process 进程
- process 对象是 Node 的一个全局对象,提供当前 Node 进程的信息,它可以在脚本的任意位置使用,不必通过 require 命令加载
属性
- process.argv :返回一个数组,包含了启动 node 进程的命令行参数
- process.env :返回包含用户环境信息的对象,可以在脚本中对这个对象进行增删改查的操作
- process.pid :返回当前进程的进程号
- process.platform :返回当前的操作系统
- process.version :返回当前 node 版本
方法
- process.cwd() :返回 node.js 进程当前工作目录
- process.chdir() :变更 node.js 进程的工作目录
- process.nextTick(fn) :将任务放到当前事件循环的尾部,添加到 “next tick” 队列,一旦当前事件轮询队列的任务全部完成,在 “next tick” 队列中的所有 callback 会被依次调用
- process.exit() :退出当前进程,很多时候是不需要的
- process.kill(pid, [signal]) :给指定进程发送信号,包括但不限于结束进程
事件
-
beforeExit 事件,在 Node 情况了 Event Loop 之后,再没有任何处理任务时触发,可以在这里部署一些任务,使得 Node 进程不退出,显示的终止程序时(
process.ext()
),不会触发 -
exit 事件,当前进程退出时触发,回调函数中只允许同步操作,因为执行完回调后,进程会退出
-
uncaughtException 事件,当前进程抛出一个没有捕获的错误时触发,可以用它在进程结束前进行一些已分配资源的同步清理操作,尝试用它来恢复应用的正常运行的操作是不安全的
专门捕捉异步代码错误,比如在 http 请求中发生错误,就可以用
process.on('uncaughtException', err => console.log('发生错误', err))
进行兜底 -
warning 事件,任何 node.js 发出的进程警告,都会触发此事件
child_process
child_process 是 node.js 中用于创建子进程的模块,node 中大名鼎鼎的 cluster 是基于它来封装的
-
exec()
异步衍生出一个 shell,然后在 shell 中执行命令,且缓冲任何产生的输出,运行结束后调用回调函数
const exec = require('child_process').exec// 回调方式 exec('ls', (err, stdout, stderr) => {if (err) {console.log('stderr', stderr)}console.log('stdout', stdout) })
由于标准输出和标准错误都是流对象(stream),可以监听 data 事件,因此上面的代码也可以写成下面这样
const { exec } = require('child_process')// 通过流的方式接受结果,类似文件读取 const child = exec('ls') child.stdout.on('data', data => {console.log('stdout:', data) }) child.stderr.on('data', data => {console.log('stderr:', data) }) child.on('close', code => {console.log('closing code:', code) })
上面的代码还有一个好处。监听 data 事件以后,可以实时输出结果,否则只有等到子进程结束,才会输出结果。所以,如果子进程进行时间较长,或是持续运行,第二种写法更好
-
execSync()
exec() 的同步版本
-
execFile()
execFile 方法直接执行特定的程序 shell,参数作为数组传入, 不会被 bash 解释,因此具有较高的安全性
execFile 会自动过滤一些敏感字符串比如:
\
const { execFile } = require('child_process')execFile('ls', ['-c'], (error, stdout, stderr) => {if (error) console.error('error', error)console.log('stdout', stdout) })
-
spawn()
spawn 方法创建一个子进程来执行特定命令 shell,用法与 execFile 方法类似,但是没有回调函数,只能通过监听事件,来获取运行结果。它属于异步执行,适用于子进程长时间运行的情况
const { spawn } = require('child_process')const child = spawn('ls')// data是Buffer child.stdout.on('data', data => console.log('data', data.toString())) child.on('close', code => console.log('code:', code))
-
fork()
fork 方法直接创建一个子进程,执行 Node 脚本,
fork('./child.js')
相当于spawn('node', ['./child.js'])
,与 spawn 方法不同的是,fork 会在父进程与子进程之间,建立一个通信管道 pipe,用于进程之间的通信,也是 IPC 通信的基础main.js
const child_process = require('child_process') const path = require('path')const child = child_process.fork(path.resolve(__dirname, './son.js')) child.on('message', data => console.log('father received:', data)) child.send('father send')
son.js
process.on('message', data => console.log('son received:', data)) process.send('hello father')
cluster 属性和方法
-
isMaster 属性,返回该进程是不是主进程。v16.0.0 废弃改为 isPrimary
-
isWorker 属性,返回该进程是不是工作进程
-
fork 方法,只能通过主进程调用,衍生出一个新的 worker 进程,返回一个 worker 对象
在
cluster.fork()
调用的时候,相当于执行了node main.js
和
child_process
的区别,不用创建一个新的child.js
-
setupMaster([settings]) 方法,用于修改 fork() 默认行为,一旦调用,将会按照 cluster.settings 进行设置。v16.0.0 废弃改为 setupPrimary
-
settings 属性,用于配置
exex: worker 文件路径
args: 传递给 worker 的参数
execArgv: 传递给 node.js 可执行文件的参数列表
cluster 事件
- fork 事件,当心的工作被 fork 时触发,可以用来记录工作进程活动,回调参数 worker 对象
- listening 事件,当一个工作进程调用
listen()
后触发,回调参数 worker 对象 - message 事件,比较特殊,需要去在单独 worker 上监听
- online 事件,复制好一个工作进程后,工作进程主动发送一条 online 消息给主进程,主进程收到消息后触发,回调参数 worker 对象
- disconnect 事件,主进程和工作进程之间 IPC 通道断开后触发
- exit 事件,有工作进程退出时触发,回调参数:worker 对象、code 退出码、signal 进程被 kill 时的信号
- setup 事件,
cluster.setupMaster()
执行后触发
const cluster = require('cluster')
const cpuNum = require('os').cpus().length
const http = require('http')const port = 8001
if (cluster.isMaster) {for (let i = 0; i < cpuNum; i++) {cluster.fork()}cluster.on('fork', worker => {console.log('主进程 fork 了一个 worker pid 为:', worker.process.pid)})cluster.on('listening', worker => {console.log('worker ' + worker.process.pid + ' died')})Object.keys(cluster.workers).forEach(id => {cluster.workers[id].on('message', data => {console.log('接收data', data)})})// 需要结合任务管理器把对应pid的任务结束cluster.on('disconnect', worker => {console.log('有工作进程退出了', worker.process.pid)})
} else {// 对应cluster.on('listening')http.createServer((req, res) => {res.writeHead(200)res.end('hello world\r\n')}).listen(port, () => {console.log(`running at: http://localhost:${port}/`)})// 对应cluster.on('message')process.send('hello')
}
cluster 多线程模型
cluster 惊群
每个 worker 进程通过使用 child_process.fork()
函数,基于 IPC(Inter-Process Communication,进程间通信),实现与 master 进程间通信
那我们直接用 child_process.fork()
实现不就行了,为什么还要用 cluster?
child_process.fork()
这样方式仅仅实现了多进程。多进程运行还涉及父子进程通信,子进程管理,以及负载均衡等问题,这些特性 cluster 帮你实现了
最初的多进程模型
最初的 node.js 多进程模型是这样实现的,master 进程创建 socket,绑定到某个地址以及端口后,自身不调用 listen 来监听连接以及 accept 连接,而是将该 socket 的 fd 传递到 fork 出来的 worker 进程,worker 接收到 fd 后再调用 listen,accept 新的连接。但实际一个新到来的连接最终只能被某一个 worker 进程 accept 再做处理,至于是哪个 worker 能够 accept 到,开发者完全无法预知以及干预。这势必就导致了当一个新连接到来时,多个 worker 进程会产生竞争,最终由胜出的 worker 获取连接
- 多个进程之间会竞争 accept 一个连接,产生惊群现象,效率比较低(4 个 worker 去抢请求)
- 由于无法控制一个新的连接由哪个进程来处理,必然导致各 worker 进程之间的负载非常不均衡
简单说来,多线程/多进程等待同一个 socket 事件,当这个事件发生时,这些线程/进程被同时唤醒,就是惊群
惊群通常发生在 server 上,当父进程绑定一个端口监听 socket,然后 fork 出多个子进程,子进程们开始循环处理(比如 accept)这个 socket。每当用户发起一个 TCP 连接时,多个子进程同时被唤醒,然后其中一个子进程 accept 新连接成功,余者皆失败,重新休眠
main.js
const net = require('net')
const { fork } = require('child_process') // 惊群const handle = net._createServerHandle('0.0.0.0', 3005)for (let i = 0; i < 4; i++) {console.log('fork', i)fork('./worker.js').send({}, handle)
}
worker.js
const net = require('net')process.on('message', (m, handle) => {start(handle)
})const buf = 'hello nodejs'
const res = ['HTTP/1.1 200 OK', 'content-length:' + buf.length].join('\r\n') + '\r\n\r\n' + bufconst data = {}function start(server) {server.listen()server.onconnection = (err, handle) => {const pid = process.pidif (!data[pid]) data[pid] = 0data[pid]++ // 每次服务+1// 最后出现抢请求现象,导致data[pid],每个处理次数不一样console.log('got a connection on worker, pid = %d', process.pid, data[pid])const socket = new net.Socket({handle: handle,})socket.readable = socket.writable = truesocket.end(res)}
}
Nginx 多线程模型
Nginx 是俄罗斯人编写的十分轻量级的 HTTP 服务器,Nginx,它的发音为 “engine X”,是一个高性能 HTTP 和反向代理服务器。异步非阻塞 I/O,而且能够高并发
- 正向代理:客户端为代理,服务器不知道客户端是谁
- 反向代理:服务器为代理。客户端不知道服务器是谁
Nginx 配置 demo:
- 一个端口挂掉整个都挂掉,且没有重启机制
http {upstream cluster {server: 127.0.0.1:3000;server: 127.0.0.1:3001;server: 127.0.0.1:3002;server: 127.0.0.1:3003;}server {listen: 80server_name www.domain.comlocation / {proxy_pass http://cluster}}
}
Nginx 的实际应用场景:比较适合稳定的服务
- 静态资源服务器 html、css、js
- 企业级集群
守护进程:退出命令行窗口之后,服务一直处于运行状态
cluster 多线程调度模型
cluster 负载均衡
cluster 是由 master 监听请求,再通过 round-robin
算法分发给各个 worker,避免惊群现象发生
round-robin
轮询调度算法 原理是每一次把来自用户的请求轮流给内部的服务器
main.js
const net = require('net')
const { fork } = require('child_process')// cluster简易版本,cluster就是基于child_process进行封装的
let workers = []
for (let i = 0; i < 4; i++) {workers.push(fork('./worker.js')) // cluster workers
}const handle = net._createServerHandle('0.0.0.0', 3005)
handle.listen()
handle.onconnection = (err, handle) => {const worker = workers.pop()worker.send({}, handle)// 通过pop和unshift实现一个简易版的轮询workers.unshift(worker)
}
worker.js
const net = require('net')process.on('message', (m, handle) => {start(handle)
})const buf = 'hello nodejs'
const res = ['HTTP/1.1 200 OK', 'content-length:' + buf.length].join('\r\n') + '\r\n\r\n' + buffunction start(server) {server.listen()server.onconnection = (err, handle) => {console.log('got a connection on worker, pid = %d', data[pid])const socket = new net.Socket({handle: handle,})socket.readable = socket.writable = truesocket.end(res)}
}
cluster 优雅退出和进程守护
cluster 中的优雅退出
- 关闭异常 Worker 进程所有的 TCP Server(将已有的连接快速断开,且不再接收新的连接),断开和 Master 的 IPC 通道,不再接受新的用户请求
- Master 立刻 fork 一个新的 Worker 进程,保证在线 【工人】总数不变
- 异常 Worker 等待一段时间,处理完已经接受的请求后退出
if (cluster.isMaster) {cluster.fork()
} else {try {//...} catch {process.disconnect()}
}
进程守护
Master 进程除了负责接收新的连接,分发给各 worker 进程处理之外,还得像天使一样默默地守护者这些 worker 进程,保障整个应用的稳定性。一旦某个 worker 进程异常退出就 fork 一个新的子进程顶替上去
这一切 cluster 模块都已经处理好了,当某个 worker 进程发生异常退出或者与 Master 进程失去联系(disconnected)时,Master 进程都会收到相应的事件通知
cluster.on('exit', () => {cluster.fork()
})cluster.on('disconnect', () => {cluster.fork()
})
IPC 通信
IPC(Inter-Process Communication,进程间的通信)
虽然每个 Worker 进程是相互对立的,但是它们之间始终还是需要通讯的,叫进程间通讯(IPC)
const cluster = require('cluster')if (cluster.isMaster) {const worker = cluster.fork()worker.send('hi there')worker.on('message', msg => {console.log(`msg: ${msg} from worker#${worker.id}`)})
} else if (cluster.isWorker) {process.on('message', msg => {process.send(msg)})
}
cluster 的 IPC 通道只存在于 Master 和 Worker 之间,Worker 与 Worker 进程互相间是没有的。Worker 之间通讯该怎么办?通过 Master 来转发
核心:worker 直接的通信,靠 master 转发,利用 worker 的 pid
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- csdn画流程图
Created with Raphal 2.3.0开始 /*定义st为start类型的节点,上面写“开始”*/输入aa...
2024/4/20 13:54:49 - JavaScript:通过点击按钮实现个人信息的录入,进而输出个人信息
内容:通过点击按钮实现个人信息的录入,进而输出个人信息。 要求:1、使用变量、字符拼接、点击事件、函数等知识。 2、一次性显示姓名、年龄、性别等个人信息。 3、使用prompt()函数、alert()函数、onclick()点击事件来实现。 代码ÿ…...
2024/5/4 14:56:10 - Apache Flink CEP 实战
本文根据Apache Flink 实战&进阶篇系列直播课程整理而成,由哈啰出行大数据实时平台资深开发刘博分享。通过一些简单的实际例子,从概念原理,到如何使用,再到功能的扩展,希望能够给打算使用或者已经使用的同学一些帮…...
2024/5/2 8:57:20 - 林业工程抗旱造林技术
【出 处】:中文核心期刊目录网http://zhongwenhexinqikan.net/ 摘要:林业工程是推动社会经济持续健康发展的重要构成要素之一。为更好地发挥林业生态及经济效益,提高造林成活率及保存率,文章从树种选择、整地、容器苗造林三个方面总结了林业…...
2024/4/21 17:29:55 - Vue项目组织描述
详细查看 Vue项目组织规范...
2024/4/21 17:29:55 - ddddddddddd
"<?xml version\"1.0\" encoding\"utf-16\"?><html><head>\r\n</head><body><table cellspacing\"0\" cellpadding\"0\" width\"100%\" border\"0\" style\"border…...
2024/4/21 17:29:53 - centos权限说明
jupyter lab无法创建文件显示Permission denied. 修改文件目录权限: sudo chmod 777 文件夹名称 权限分别是rwx,依次是所有者,组用户和其他用户 查看文件权限:ls -l filename 查看文件夹名称:ls -ld filepackagename...
2024/4/21 17:29:53 - 2021-10-27机器学习Day1
ata.insert(0,Ones,1) colsdata.shape[1] print(cols)...
2024/4/21 17:29:51 - 21天打卡活动 leetcode 301
21天打卡活动 leetcode 301 首先利用括号匹配得出多余的括号数用lremove 和rremove记录; 然后进行剪枝,也就是利用括号左右匹配的特点来进行删除括号,同时用两个记录数记录左右括号数,不匹配时即停止,返回不合法。当多…...
2024/4/21 17:29:50 - 【AtCoder】D - Cooking 动态规划
题 参考 #include<bits/stdc.h> using namespace std; typedef long long ll; #define mem(a,x) memset(a,x,sizeof(a)); #define fir(i,a,n) for(int ia;i<n;i) // const int N105,M1e510; int a[N],dp[N][M];//前i个菜是否能用j分钟恰好完成 int n; int sum0; int…...
2024/4/21 17:29:49 - 生态模式下的林业栽培管理技术探析
【出 处】:中文核心期刊目录网 摘要:社会人口规模不断增长,林业资源的消费量随之上升。运用生态林业模式,有望于寻求经济效益与生态环境保护间的平衡。栽培管理技术属于林业生产的关键技术,本文简要分析探讨了在新时…...
2024/4/21 17:29:49 - 2021-10-27 数据结构学习-贪婪算法01
问:1列站成队的孩子成绩各不相同,老师分发糖果给每个人,且每个孩子至少会分得到一个,而成绩更好的孩子分得的糖果比左右的孩子多一个,求需要的糖果总数。 思路:所有孩子至少会分得到一个糖果,所…...
2024/4/21 17:29:48 - 电脑安装双系统教程,电脑安装两个系统
现在很多新电脑预装的都是win10系统了,有些网友不习惯使用win10,想给电脑安装双系统,这样方便切换不同的系统使用.那么如何给电脑安装双系统?下面就给大家演示下电脑安装双系统的方法. 1.右键点击计算机,选择管理选项。 2.在打开的计算机管理窗口中,选择…...
2024/4/21 17:29:47 - 小白开始学编程之Python
买了小甲鱼的书然后看了看第一节,尝试了一下编程...
2024/5/3 18:05:24 - php 解析excel 表格的数据方法
1、获取本地某个excel 的数据,如表格 2、做成动态的数据,如按照一定的表格样式构建数据,然后上传,获取文件地址,开始解析excel,获取数据 以上两个方法都可以用如下方法,便可以解析出excel 里面的数据 publ…...
2024/5/3 0:40:24 - C#中三层架构UI、BLL、DAL、Model详解
三层架构分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)再加上实体类库(Model) 1、实体类库(Model),主要存放数据库中的表字段。…...
2024/5/3 22:56:36 - leetcode110
就是利用上一道题的代码稍微改了一下,根据他们的深度判断是否是平衡二叉树。递归没我想的那么简单,尽管明白了线程的运行机制,可是会发现每次把参数传进去和把它当作全局变量,不同地方的判断语句都会有不一样的效果,还…...
2024/4/23 14:56:11 - Linux系统常用命令(持续更新)
1、运行sh文件: (1) bash 1.sh (2) sh 1.sh...
2024/4/25 13:58:51 - NY8B062D 九齐单片机之ADC芯片
概述 NY8B062E 是以EPROM作為記憶體的 8 位元微控制器,專為家電或量測等等的I/O應用設計。採用CMOS製程並同 時提供客戶低成本、高性能、及高性價比等顯著優勢。NY8B062E 核心建立在RISC精簡指令集架構可以很容易地做 編輯和控制,共有 55 條指令。除了少…...
2024/5/3 20:26:28 - Vue的v-bind及class与style的绑定
文章目录一、绑定class的几种方式1.对象语法(使用v-bind)2.数组语法(使用v-bind)二、绑定内联样式一、绑定class的几种方式 1.对象语法(使用v-bind) 给v-bind设置一个对象,可以动态的绑定clas…...
2024/4/20 13:55:02
最新文章
- golang学习笔记(协程的基础知识)
golang的协程 协程是一种轻量级的线程,它可以实现并发执行的并行操作。协程是Go语言中的一个核心特性,它使得程序能够以并发的方式运行,并且非常高效。与传统的线程相比,协程的创建和销毁成本非常低,可以方便地启动大…...
2024/5/4 15:11:35 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - [C++/Linux] UDP编程
一. UDP函数 UDP(用户数据报协议,User Datagram Protocol)是一种无连接的网络协议,用于在互联网上交换数据。它允许应用程序发送数据报给另一端的应用程序,但不保证数据报能成功到达,也就是说,它…...
2024/5/3 8:59:07 - 解决前端性能瓶颈:高效处理大量数据渲染与复杂交互的策略与优化方法
✨✨祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心!✨✨ 🎈🎈作者主页: 喔的嘛呀🎈🎈 目录 引言 一、分页加载数据 二、虚拟滚动 三、懒加载 四、数据缓存 五、减少重绘和回流 …...
2024/5/1 13:30:31 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/3 23:10:03 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/2 15:04:34 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/4 2:59:34 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57