首页 文章 精选 留言 我的

精选列表

搜索[node.js],共4383篇文章
优秀的个人博客,低调大师

Node.js 中 stream.pipeline 与 async 迭代器的混合使用:避免背压失控和内存泄漏

在处理大文件上传、日志转发或者数据库游标导出时,很多人会把 `fs.createReadStream` 和 `fs.createWriteStream` 直接通过 `.pipe()` 连起来。这种写法在数据量小的时候跑得很顺,但一旦下游写入变慢或者中间需要插入自定义转换逻辑,问题就暴露出来了:可读流继续按自己的节奏生产数据,可写流的内部缓冲区越堆越高,最终进程内存飙升,甚至因为 `write after end` 或者未捕获的 error 事件直接崩掉。`stream.pipeline` 本身解决了错误传递和流生命周期管理,但它和 async 迭代器混用时,背压的处理方式很容易被误解。这篇内容围绕一个真实的日志采集场景,梳理 `pipeline`、`for await...of` 以及手动 `highWaterMark` 配合时的行为差异,给出能直接落地的代码写法。 先看一个常见的错误写法。假设要把一个不断追加的日志文件按行过滤后转发到另一个可写流,中间做一下脱敏。有人会这样写: ```js const { createReadStream, createWriteStream } = require('fs'); const { pipeline } = require('stream/promises'); const { Transform } = require('stream'); const reader = createReadStream('/var/log/app.log'); const writer = createWriteStream('/data/clean.log'); const masker = new Transform({ transform(chunk, enc, cb) { const text = chunk.toString().replace(/token=\w+/g, 'token=***'); cb(null, text); } }); await pipeline(reader, masker, writer); ``` 这个写法本身没问题,`pipeline` 会在任意一环出错时销毁所有流并 reject。但问题出在 masker 的 `transform` 里直接 `chunk.toString()`:如果日志里有多字节字符恰好被切在 chunk 边界上,就会出现乱码或替换错位。更隐蔽的是,当 writer 的下游是网络套接字、写入延迟抖动大时,`pipeline` 确实会尊重背压,但 Transform 的 `highWaterMark` 默认 16KB,如果单条日志超过这个长度,`transform` 回调里处理完的字符串长度可能远超写入端的消费能力,缓冲区仍然会短暂堆积。 要手动控制节奏,可以改用 async 迭代器从可读流拉取数据,但别用 `for await (const chunk of reader)` 然后逐块 `writer.write()` 并忽略返回值。`writer.write()` 返回 false 时表示缓冲区已满,必须等待 `drain` 事件再继续。下面的写法把背压显式暴露出来: ```js const { once } = require('events'); async function copyWithBackpressure(reader, writer, mask) { for await (const chunk of reader) { const text = mask(chunk); if (!writer.write(text)) { await once(writer, 'drain'); } } writer.end(); } ``` 这段代码在 `write` 返回 false 时会挂起当前迭代,直到可写流排空,天然形成拉取式节奏。注意 `once(writer, 'drain')` 要放在 `write` 之后、下一次迭代之前,否则会丢掉一次 drain 信号。另外,如果 writer 在等待期间报错,`once` 不会自动处理 error 事件,需要配合 `AbortController` 或者在外层用 `Promise.race` 监听 `error`,否则进程会因未处理的 error 事件退出。 实际项目里更稳妥的做法是让 `pipeline` 和 async 迭代器各司其职:把需要异步拉取的上游(比如分页 API、数据库游标)封装成 `Readable.from`,再交给 `pipeline` 去对接下游转换和写入。这样背压由 `pipeline` 统一管理,又保留了 async 生成器的可读性: ```js const { Readable } = require('stream'); const { pipeline } = require('stream/promises'); async function* fetchPages(client) { let cursor = null; do { const page = await client.list({ cursor, limit: 200 }); for (const item of page.items) { yield JSON.stringify(item) + '\n'; } cursor = page.nextCursor; } while (cursor); } await pipeline( Readable.from(fetchPages(apiClient), { objectMode: false }), new Transform({ transform(chunk, enc, cb) { cb(null, chunk); } }), createWriteStream('/data/export.ndjson') ); ``` 这里 `Readable.from` 对异步生成器做了适配,生成器 `yield` 的节奏受下游消费速度约束;`pipeline` 负责在任意流出错时调用 `destroy()`,避免生成器里的游标资源泄漏。需要留心的一点是 `Readable.from` 默认 `objectMode: true`,如果 `yield` 出来的是字符串又不想让下游按对象模式处理,记得显式传 `objectMode: false`,否则 `createWriteStream` 收到的是对象而不是 Buffer,会直接抛类型错误。 排查这类问题时,`stream.pipeline` 的错误对象里会带上 `code` 和出错的流实例,但不会告诉你当时各个流的缓冲水位。可以在关键 Transform 上挂一个定时器打印 `readableLength` 和 `writableLength`,或者用 `process.memoryUsage().heapUsed` 在 chunk 到达时做采样。如果发现 `writableLength` 持续接近 `highWaterMark` 但从不触发 drain,检查一下是不是转换逻辑里忽略了 `write` 的返回值,或者把 `writer.write` 放在了 `setInterval` 之类的异步回调里,导致背压信号根本没被消费。 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1601.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1602.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1603.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1604.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1605.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1606.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1607.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1608.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1609.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1610.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1611.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1612.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1613.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1614.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1615.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1616.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1617.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1618.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1619.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1620.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1621.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1622.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1623.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1624.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1625.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1626.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1627.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1628.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1629.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1630.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1631.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1632.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1633.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1634.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1635.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1636.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1637.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1638.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1639.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1640.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1641.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1642.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1643.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1644.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1645.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1646.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1647.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1648.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1649.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1650.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1651.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1652.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1653.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1654.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1655.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1656.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1657.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1658.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1659.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1660.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1661.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1662.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1663.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1664.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1665.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1666.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1667.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1668.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1669.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1670.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1671.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1672.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1673.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1674.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1675.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1676.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1677.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1678.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1679.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1680.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1681.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1682.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1683.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1684.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1685.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1686.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1687.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1688.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1689.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1690.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1691.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1692.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1693.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1694.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1695.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1696.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1697.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1698.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1699.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1700.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1701.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1702.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1703.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1704.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1705.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1706.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1707.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1708.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1709.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1710.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1711.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1712.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1713.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1714.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1715.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1716.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1717.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1718.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1719.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1720.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1721.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1722.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1723.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1724.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1725.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1726.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1727.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1728.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1729.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1730.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1731.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1732.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1733.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1734.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1735.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1736.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1737.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1738.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1739.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1740.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1741.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1742.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1743.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1744.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1745.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1746.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1747.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1748.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1749.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1750.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1751.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1752.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1753.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1754.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1755.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1756.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1757.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1758.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1759.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1760.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1761.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1762.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1763.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1764.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1765.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1766.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1767.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1768.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1769.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1770.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1771.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1772.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1773.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1774.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1775.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1776.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1777.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1778.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1779.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1780.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1781.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1782.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1783.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1784.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1785.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1786.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1787.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1788.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1789.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1790.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1791.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1792.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1793.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1794.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1795.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1796.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1797.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1798.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1799.html 推荐查看天气:http://www.tianqi98.com/jizhuanwan/1800.html

优秀的个人博客,低调大师

Node.js 里用 worker_threads 处理 CPU 密集任务时,为什么你的进程还是卡住了

线上有个报表导出的接口,用户点一下要等十几秒,期间整个 Node 服务像死了一样,连健康检查都超时。排查下来不是数据库慢,而是导出逻辑里有一段对几万行数据做排序和格式化的纯计算。很多人第一反应是开个 `worker_threads` 把计算丢进去,结果发现主线程还是卡,甚至更慢了。问题往往不在 worker 本身,而在于数据怎么传、worker 怎么复用、以及主线程有没有在做本该交给 worker 的事情。这篇聊几个实际踩过的点:结构化克隆的隐藏成本、worker 池的必要性、SharedArrayBuffer 的适用边界,以及如何确认计算真的离开了主线程。 先看一个最朴素的写法,也是大多数人第一次用 worker 的写法: ```js // main.js const { Worker } = require('worker_threads'); function exportReport(rows) { return new Promise((resolve, reject) => { const worker = new Worker('./report-worker.js', { workerData: rows, }); worker.on('message', resolve); worker.on('error', reject); }); } app.get('/export', async (req, res) => { const rows = await db.query('select * from orders'); const result = await exportReport(rows); res.send(result); }); ``` ```js // report-worker.js const { parentPort, workerData } = require('worker_threads'); const rows = workerData; rows.sort((a, b) => b.amount - a.amount); const csv = rows.map(r => `${r.id},${r.amount}`).join('\n'); parentPort.postMessage(csv); ``` 这段代码能跑,但有两个不明显的问题。第一,`workerData` 传给 worker 时走的是结构化克隆算法,几万行对象会被完整复制一份,这个序列化和反序列化是在主线程发起的,数据量一大,主线程照样要花时间。第二,每个请求都新建一个 Worker,线程创建本身有开销,并发几个导出请求,机器上瞬间多出一堆线程,内存和上下文切换都上来了。 worker 的启动成本比想象中高。一个空 Worker 从创建到能收消息,通常在几十毫秒量级,还要加载模块。导出接口如果是低频调用,单次创建还能接受;一旦有并发或者被轮询,就必须用池子。 自己写个简单的池并不复杂,核心就是维护固定数量的 worker,用队列分发任务,任务完成后再把 worker 放回空闲列表: ```js class WorkerPool { constructor(size, workerPath) { this.idle = []; this.queue = []; for (let i = 0; i { const task = w._task; w._task = null; task.resolve(msg); this.release(w); }); w.on('error', (err) => { const task = w._task; w._task = null; if (task) task.reject(err); this.release(w); }); this.idle.push(w); } } run(payload) { return new Promise((resolve, reject) => { const task = { payload, resolve, reject }; const w = this.idle.pop(); if (w) { w._task = task; w.postMessage(payload); } else { this.queue.push(task); } }); } release(w) { const next = this.queue.shift(); if (next) { w._task = next; w.postMessage(next.payload); } else { this.idle.push(w); } } } ``` 注意错误分支里也要 `release`,否则一个 worker 抛错后池子容量就永久少一个,跑久了会卡死。 数据传递这块,如果只是把行数据发过去算完再发回来,克隆成本绕不开。几个实际的取舍: 如果 worker 只需要读数据、不需要改,可以考虑把数据序列化成 Buffer 或字符串再传,clone 一个 Buffer 比 clone 几万个对象便宜得多,worker 里再自己解析。代价是多一次编解码,要看你数据结构。 如果主线程和 worker 要共享大块二进制数据,比如图像像素、定长数组,用 `SharedArrayBuffer` 或 `transferList` 转移 `ArrayBuffer` 的所有权,避免复制。但共享内存要自己处理并发写,普通业务数据用不上。 还有一种情况是主线程还在做重活。比如导出前先 `rows.map` 一遍筛选,或者把 worker 返回的 CSV 再用 `join` 拼一次,这些都在主线程上跑,worker 再快也没用。计算逻辑要整体搬进 worker,包括中间的格式化。 验证计算是不是真离开了主线程,别靠感觉。可以在主线程上打点,看事件循环的延迟: ```js let last = Date.now(); setInterval(() => { const now = Date.now(); const lag = now - last - 100; if (lag > 50) console.warn('event loop lag', lag, 'ms'); last = now; }, 100).unref(); ``` 导出请求打进来时如果这个 lag 飙到几百毫秒,说明主线程被占着。常见原因是 worker 消息发出去之前主线程就在做大对象的序列化,或者结果返回后主线程又做了一次重计算。 最后提一个容易被忽略的:worker 里不要持有数据库连接或者做异步 IO 密集的事。worker 适合纯 CPU 计算,IO 还是放主线程用连接池更省资源。把导出逻辑拆成「主线程查数据、worker 算、主线程回写响应」,中间只传必要字段,往往比一股脑把整个结果集丢过去更稳。 推荐查看天气:http://www.shuyiwang.cn/ 推荐查看天气:http://www.shuyiwang.cn/search.html 推荐查看天气:http://www.shuyiwang.cn/search/anime.html 推荐查看天气:http://www.shuyiwang.cn/bushou.html 推荐查看天气:http://www.shuyiwang.cn/bihua.html 推荐查看天气:http://www.shuyiwang.cn/resource/rules.html 推荐查看天气:http://www.shuyiwang.cn/resource/culture.html 推荐查看天气:http://www.shuyiwang.cn/resource/tips.html 推荐查看天气:http://www.shuyiwang.cn/about.html 推荐查看天气:http://www.shuyiwang.cn/zi/1.html 推荐查看天气:http://www.shuyiwang.cn/zi/2.html 推荐查看天气:http://www.shuyiwang.cn/zi/3.html 推荐查看天气:http://www.shuyiwang.cn/zi/4.html 推荐查看天气:http://www.shuyiwang.cn/zi/5.html 推荐查看天气:http://www.shuyiwang.cn/zi/6.html 推荐查看天气:http://www.shuyiwang.cn/zi/7.html 推荐查看天气:http://www.shuyiwang.cn/zi/8.html 推荐查看天气:http://www.shuyiwang.cn/zi/9.html 推荐查看天气:http://www.shuyiwang.cn/zi/10.html 推荐查看天气:http://www.shuyiwang.cn/zi/11.html 推荐查看天气:http://www.shuyiwang.cn/zi/12.html 推荐查看天气:http://www.shuyiwang.cn/zi/13.html 推荐查看天气:http://www.shuyiwang.cn/zi/14.html 推荐查看天气:http://www.shuyiwang.cn/zi/15.html 推荐查看天气:http://www.shuyiwang.cn/zi/16.html 推荐查看天气:http://www.shuyiwang.cn/zi/17.html 推荐查看天气:http://www.shuyiwang.cn/zi/18.html 推荐查看天气:http://www.shuyiwang.cn/zi/19.html 推荐查看天气:http://www.shuyiwang.cn/zi/20.html 推荐查看天气:http://www.shuyiwang.cn/zi/21.html 推荐查看天气:http://www.shuyiwang.cn/zi/22.html 推荐查看天气:http://www.shuyiwang.cn/zi/23.html 推荐查看天气:http://www.shuyiwang.cn/zi/24.html 推荐查看天气:http://www.shuyiwang.cn/zi/25.html 推荐查看天气:http://www.shuyiwang.cn/zi/26.html 推荐查看天气:http://www.shuyiwang.cn/zi/27.html 推荐查看天气:http://www.shuyiwang.cn/zi/28.html 推荐查看天气:http://www.shuyiwang.cn/zi/29.html 推荐查看天气:http://www.shuyiwang.cn/zi/30.html 推荐查看天气:http://www.shuyiwang.cn/zi/31.html 推荐查看天气:http://www.shuyiwang.cn/zi/32.html 推荐查看天气:http://www.shuyiwang.cn/zi/33.html 推荐查看天气:http://www.shuyiwang.cn/zi/34.html 推荐查看天气:http://www.shuyiwang.cn/zi/35.html 推荐查看天气:http://www.shuyiwang.cn/zi/36.html 推荐查看天气:http://www.shuyiwang.cn/zi/37.html 推荐查看天气:http://www.shuyiwang.cn/zi/38.html 推荐查看天气:http://www.shuyiwang.cn/zi/39.html 推荐查看天气:http://www.shuyiwang.cn/zi/40.html 推荐查看天气:http://www.shuyiwang.cn/zi/41.html 推荐查看天气:http://www.shuyiwang.cn/zi/42.html 推荐查看天气:http://www.shuyiwang.cn/zi/43.html 推荐查看天气:http://www.shuyiwang.cn/zi/44.html 推荐查看天气:http://www.shuyiwang.cn/zi/45.html 推荐查看天气:http://www.shuyiwang.cn/zi/46.html 推荐查看天气:http://www.shuyiwang.cn/zi/47.html 推荐查看天气:http://www.shuyiwang.cn/zi/48.html 推荐查看天气:http://www.shuyiwang.cn/zi/49.html 推荐查看天气:http://www.shuyiwang.cn/zi/50.html 推荐查看天气:http://www.shuyiwang.cn/zi/51.html 推荐查看天气:http://www.shuyiwang.cn/zi/52.html 推荐查看天气:http://www.shuyiwang.cn/zi/53.html 推荐查看天气:http://www.shuyiwang.cn/zi/54.html 推荐查看天气:http://www.shuyiwang.cn/zi/55.html 推荐查看天气:http://www.shuyiwang.cn/zi/56.html 推荐查看天气:http://www.shuyiwang.cn/zi/57.html 推荐查看天气:http://www.shuyiwang.cn/zi/58.html 推荐查看天气:http://www.shuyiwang.cn/zi/59.html 推荐查看天气:http://www.shuyiwang.cn/zi/60.html 推荐查看天气:http://www.shuyiwang.cn/zi/61.html 推荐查看天气:http://www.shuyiwang.cn/zi/62.html 推荐查看天气:http://www.shuyiwang.cn/zi/63.html 推荐查看天气:http://www.shuyiwang.cn/zi/64.html 推荐查看天气:http://www.shuyiwang.cn/zi/65.html 推荐查看天气:http://www.shuyiwang.cn/zi/66.html 推荐查看天气:http://www.shuyiwang.cn/zi/67.html 推荐查看天气:http://www.shuyiwang.cn/zi/68.html 推荐查看天气:http://www.shuyiwang.cn/zi/69.html 推荐查看天气:http://www.shuyiwang.cn/zi/70.html 推荐查看天气:http://www.shuyiwang.cn/zi/71.html 推荐查看天气:http://www.shuyiwang.cn/zi/72.html 推荐查看天气:http://www.shuyiwang.cn/zi/73.html 推荐查看天气:http://www.shuyiwang.cn/zi/74.html 推荐查看天气:http://www.shuyiwang.cn/zi/75.html 推荐查看天气:http://www.shuyiwang.cn/zi/76.html 推荐查看天气:http://www.shuyiwang.cn/zi/77.html 推荐查看天气:http://www.shuyiwang.cn/zi/78.html 推荐查看天气:http://www.shuyiwang.cn/zi/79.html 推荐查看天气:http://www.shuyiwang.cn/zi/80.html 推荐查看天气:http://www.shuyiwang.cn/zi/81.html 推荐查看天气:http://www.shuyiwang.cn/zi/82.html 推荐查看天气:http://www.shuyiwang.cn/zi/83.html 推荐查看天气:http://www.shuyiwang.cn/zi/84.html 推荐查看天气:http://www.shuyiwang.cn/zi/85.html 推荐查看天气:http://www.shuyiwang.cn/zi/86.html 推荐查看天气:http://www.shuyiwang.cn/zi/87.html 推荐查看天气:http://www.shuyiwang.cn/zi/88.html 推荐查看天气:http://www.shuyiwang.cn/zi/89.html 推荐查看天气:http://www.shuyiwang.cn/zi/90.html 推荐查看天气:http://www.shuyiwang.cn/zi/91.html 推荐查看天气:http://www.shuyiwang.cn/zi/92.html 推荐查看天气:http://www.shuyiwang.cn/zi/93.html 推荐查看天气:http://www.shuyiwang.cn/zi/94.html 推荐查看天气:http://www.shuyiwang.cn/zi/95.html 推荐查看天气:http://www.shuyiwang.cn/zi/96.html 推荐查看天气:http://www.shuyiwang.cn/zi/97.html 推荐查看天气:http://www.shuyiwang.cn/zi/98.html 推荐查看天气:http://www.shuyiwang.cn/zi/99.html 推荐查看天气:http://www.shuyiwang.cn/zi/100.html 推荐查看天气:http://www.shuyiwang.cn/zi/101.html 推荐查看天气:http://www.shuyiwang.cn/zi/102.html 推荐查看天气:http://www.shuyiwang.cn/zi/103.html 推荐查看天气:http://www.shuyiwang.cn/zi/104.html 推荐查看天气:http://www.shuyiwang.cn/zi/105.html 推荐查看天气:http://www.shuyiwang.cn/zi/106.html 推荐查看天气:http://www.shuyiwang.cn/zi/107.html 推荐查看天气:http://www.shuyiwang.cn/zi/108.html 推荐查看天气:http://www.shuyiwang.cn/zi/109.html 推荐查看天气:http://www.shuyiwang.cn/zi/110.html 推荐查看天气:http://www.shuyiwang.cn/zi/111.html 推荐查看天气:http://www.shuyiwang.cn/zi/112.html 推荐查看天气:http://www.shuyiwang.cn/zi/113.html 推荐查看天气:http://www.shuyiwang.cn/zi/114.html 推荐查看天气:http://www.shuyiwang.cn/zi/115.html 推荐查看天气:http://www.shuyiwang.cn/zi/116.html 推荐查看天气:http://www.shuyiwang.cn/zi/117.html 推荐查看天气:http://www.shuyiwang.cn/zi/118.html 推荐查看天气:http://www.shuyiwang.cn/zi/119.html 推荐查看天气:http://www.shuyiwang.cn/zi/120.html 推荐查看天气:http://www.shuyiwang.cn/zi/121.html 推荐查看天气:http://www.shuyiwang.cn/zi/122.html 推荐查看天气:http://www.shuyiwang.cn/zi/123.html 推荐查看天气:http://www.shuyiwang.cn/zi/124.html 推荐查看天气:http://www.shuyiwang.cn/zi/125.html 推荐查看天气:http://www.shuyiwang.cn/zi/126.html 推荐查看天气:http://www.shuyiwang.cn/zi/127.html 推荐查看天气:http://www.shuyiwang.cn/zi/128.html 推荐查看天气:http://www.shuyiwang.cn/zi/129.html 推荐查看天气:http://www.shuyiwang.cn/zi/130.html 推荐查看天气:http://www.shuyiwang.cn/zi/131.html 推荐查看天气:http://www.shuyiwang.cn/zi/132.html 推荐查看天气:http://www.shuyiwang.cn/zi/133.html 推荐查看天气:http://www.shuyiwang.cn/zi/134.html 推荐查看天气:http://www.shuyiwang.cn/zi/135.html 推荐查看天气:http://www.shuyiwang.cn/zi/136.html 推荐查看天气:http://www.shuyiwang.cn/zi/137.html 推荐查看天气:http://www.shuyiwang.cn/zi/138.html 推荐查看天气:http://www.shuyiwang.cn/zi/139.html 推荐查看天气:http://www.shuyiwang.cn/zi/140.html 推荐查看天气:http://www.shuyiwang.cn/zi/141.html 推荐查看天气:http://www.shuyiwang.cn/zi/142.html 推荐查看天气:http://www.shuyiwang.cn/zi/143.html 推荐查看天气:http://www.shuyiwang.cn/zi/144.html 推荐查看天气:http://www.shuyiwang.cn/zi/145.html 推荐查看天气:http://www.shuyiwang.cn/zi/146.html 推荐查看天气:http://www.shuyiwang.cn/zi/147.html 推荐查看天气:http://www.shuyiwang.cn/zi/148.html 推荐查看天气:http://www.shuyiwang.cn/zi/149.html 推荐查看天气:http://www.shuyiwang.cn/zi/150.html 推荐查看天气:http://www.shuyiwang.cn/zi/151.html 推荐查看天气:http://www.shuyiwang.cn/zi/152.html 推荐查看天气:http://www.shuyiwang.cn/zi/153.html 推荐查看天气:http://www.shuyiwang.cn/zi/154.html 推荐查看天气:http://www.shuyiwang.cn/zi/155.html 推荐查看天气:http://www.shuyiwang.cn/zi/156.html 推荐查看天气:http://www.shuyiwang.cn/zi/157.html 推荐查看天气:http://www.shuyiwang.cn/zi/158.html 推荐查看天气:http://www.shuyiwang.cn/zi/159.html 推荐查看天气:http://www.shuyiwang.cn/zi/160.html 推荐查看天气:http://www.shuyiwang.cn/zi/161.html 推荐查看天气:http://www.shuyiwang.cn/zi/162.html 推荐查看天气:http://www.shuyiwang.cn/zi/163.html 推荐查看天气:http://www.shuyiwang.cn/zi/164.html 推荐查看天气:http://www.shuyiwang.cn/zi/165.html 推荐查看天气:http://www.shuyiwang.cn/zi/166.html 推荐查看天气:http://www.shuyiwang.cn/zi/167.html 推荐查看天气:http://www.shuyiwang.cn/zi/168.html 推荐查看天气:http://www.shuyiwang.cn/zi/169.html 推荐查看天气:http://www.shuyiwang.cn/zi/170.html 推荐查看天气:http://www.shuyiwang.cn/zi/171.html 推荐查看天气:http://www.shuyiwang.cn/zi/172.html 推荐查看天气:http://www.shuyiwang.cn/zi/173.html 推荐查看天气:http://www.shuyiwang.cn/zi/174.html 推荐查看天气:http://www.shuyiwang.cn/zi/175.html 推荐查看天气:http://www.shuyiwang.cn/zi/176.html 推荐查看天气:http://www.shuyiwang.cn/zi/177.html 推荐查看天气:http://www.shuyiwang.cn/zi/178.html 推荐查看天气:http://www.shuyiwang.cn/zi/179.html 推荐查看天气:http://www.shuyiwang.cn/zi/180.html 推荐查看天气:http://www.shuyiwang.cn/zi/181.html 推荐查看天气:http://www.shuyiwang.cn/zi/182.html 推荐查看天气:http://www.shuyiwang.cn/zi/183.html 推荐查看天气:http://www.shuyiwang.cn/zi/184.html 推荐查看天气:http://www.shuyiwang.cn/zi/185.html 推荐查看天气:http://www.shuyiwang.cn/zi/186.html 推荐查看天气:http://www.shuyiwang.cn/zi/187.html 推荐查看天气:http://www.shuyiwang.cn/zi/188.html 推荐查看天气:http://www.shuyiwang.cn/zi/189.html 推荐查看天气:http://www.shuyiwang.cn/zi/190.html 推荐查看天气:http://www.shuyiwang.cn/zi/191.html

优秀的个人博客,低调大师

Node.js 中 fs.watch 和 fs.watchFile 到底该用哪个?一次文件监听踩坑记录

最近在做一个本地 Markdown 笔记工具,需要监听笔记目录下的文件变化,实时刷新预览。一开始随手用了 fs.watch,在本机 macOS 上跑得好好的,结果同事在 Windows 上测试时发现重命名文件会触发两次事件,还有时候改完内容要等好几秒才刷新。换成 fs.watchFile 之后延迟又高得离谱。这两个 API 名字像、行为差得远,官方文档写得也比较克制,实际用起来坑不少。这篇文章梳理一下两者的底层机制差异、各自适合的场景,以及在跨平台环境下怎么写一个相对可靠的封装,顺带聊聊 chokidar 这类库为什么存在。

优秀的个人博客,低调大师

Node.js 里用 worker_threads 处理 CPU 密集任务时,为什么你的主线程还是卡住了

线上有个图片处理服务,用户上传一张 4MB 左右的 JPEG,服务端要生成三档缩略图并做一次水印合成。一开始用的是 sharp 的同步链式调用,在测试环境跑得挺顺,结果上线后一到下午高峰,接口 P99 直接飙到 3 秒以上,健康检查也开始超时。第一反应是把整个处理逻辑塞进 worker_threads,毕竟 sharp 本身是 libvips 的绑定,跑在 worker 里应该能把主线程释放出来。改完之后吞吐确实上了一个台阶,但监控上还是能看到事件循环延迟有周期性尖峰,偶尔能到 400ms 以上。排查下来发现 worker 的创建方式、消息传递的数据形态、以及线程池默认大小这三处都有坑,而且它们叠在一起时,主线程依然会被拖住。这篇文章把这段改造里踩到的几个真实问题拆开讲清楚,包括 worker 复用的正确姿势、Transferable 和 Structured Clone 对序列化开销的影响,以及怎么用 event loop delay 把问题量化出来。 先说 worker 的创建方式。很多人会在每次请求进来时 `new Worker('./image-worker.js')`,用完就 `terminate()`。这个写法看起来最干净,实际上 worker 的启动成本不低:要加载模块、初始化 libvips、分配线程池,单次冷启动在普通云主机上测下来大概 30~80ms。请求一多,这些启动动作会挤在主线程的 event loop 里排队,再加上频繁创建销毁带来的 GC 压力,延迟尖峰就出来了。合理的做法是维护一个固定大小的 worker 池,启动时预热,请求来了从池里取空闲的实例,处理完归还。下面是一个最小可用的池实现,没有依赖任何三方库: ```js const { Worker } = require('node:worker_threads'); const path = require('node:path'); class WorkerPool { constructor(size, workerPath) { this.size = size; this.workerPath = workerPath; this.idle = []; this.queue = []; this.workers = new Set(); for (let i = 0; i { const task = worker._currentTask; if (!task) return; if (msg.error) task.reject(new Error(msg.error)); else task.resolve(msg.result); worker._currentTask = null; this.#release(worker); }); worker.on('error', (err) => { const task = worker._currentTask; if (task) { task.reject(err); worker._currentTask = null; } this.workers.delete(worker); this.#spawn(); }); this.workers.add(worker); this.idle.push(worker); } #release(worker) { if (this.queue.length) { const task = this.queue.shift(); worker._currentTask = task; worker.postMessage(task.payload); } else { this.idle.push(worker); } } run(payload) { return new Promise((resolve, reject) => { const worker = this.idle.pop(); const task = { resolve, reject, payload }; if (worker) { worker._currentTask = task; worker.postMessage(payload); } else { this.queue.push(task); } }); } } const pool = new WorkerPool(4, path.join(__dirname, 'image-worker.js')); ``` worker 侧的代码很直白,收到 buffer 就调 sharp,处理完把结果 postMessage 回去。但这里有个容易被忽略的点:`postMessage` 默认走的是 Structured Clone 算法,一个 4MB 的 Buffer 会被完整拷贝一份,拷贝发生在主线程发消息和 worker 收消息两个环节。高峰期每秒几十个请求,光序列化就能把主线程的 CPU 吃满。解决办法是 Buffer 底层是 ArrayBuffer,只要把这块内存的所有权转移出去,就不需要拷贝: ```js // image-worker.js const { parentPort } = require('node:worker_threads'); const sharp = require('sharp'); parentPort.on('message', async (payload) => { try { const { buffer, width, height } = payload; const result = await sharp(buffer) .resize(width, height, { fit: 'inside' }) .jpeg({ quality: 82 }) .toBuffer(); const ab = result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength); parentPort.postMessage( { result: ab }, [ab] ); } catch (err) { parentPort.postMessage({ error: err.message }); } }); ``` 主线程发送时也要带上 transfer list: ```js const ab = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); pool.run({ buffer: ab, width: 800, height: 800 }, [ab]); ``` 注意 transfer 之后主线程这边的 ArrayBuffer 会被 detach,长度变成 0,如果后续还要拿原始 buffer 做别的事,必须先拷贝一份再转移。曾经因为忘了这点,上传原图的逻辑在 worker 返回后读到了空 buffer,调试了半小时才发现是 detach 惹的祸。 另一个影响事件循环延迟的因素是 libvips 自己的线程池。sharp 内部用 libvips,libvips 默认会根据 CPU 核数开一组工作线程,如果用 `UV_THREADPOOL_SIZE` 去调 Node 的线程池,对 sharp 没有效果。真正起作用的是环境变量 `VIPS_CONCURRENCY`,在容器里如果 CPU limit 配得比实际核数高,libvips 会按宿主机核数开线程,反而造成线程争抢。我们最后是显式设成每个 worker 单线程: ```bash VIPS_CONCURRENCY=1 node server.js ``` worker 池本身承担并发,单个 worker 内部再把 libvips 的并发压到 1,这样每个容器实例的 CPU 占用是可预测的,扩容时也不会因为线程数失控而互相踩。 改完之后还得有手段验证效果,不能靠体感。Node 从 18 开始提供了 `performance.eventLoopUtilization()`,可以周期性采样主线程的事件循环利用率,方法本身开销很低,放在一个 `setInterval` 里就行: ```js const { performance } = require('node:perf_hooks'); let last = performance.eventLoopUtilization(); setInterval(() => { const now = performance.eventLoopUtilization(); const delta = performance.eventLoopUtilization(now, last); if (delta.utilization > 0.85) { console.warn('event loop busy', delta.utilization.toFixed(2)); } last = now; }, 1000).unref(); ``` 这个指标比单纯看 CPU 更贴近用户感知,因为事件循环被占住时,CPU 使用率可能并不高,请求却全都卡在队列里。把 worker 池大小、消息体积、libvips 并发这三项对齐之后,接口 P99 稳定在 400ms 左右,健康检查再没报过超时。后面如果还要继续压延迟,下一个该动的地方是把缩略图结果直接写进对象存储的流里,省掉 worker 到主线程再回传 buffer 这一趟。 推荐查看天气:http://www.tianqi556.com/chengyu/85.html 推荐查看天气:http://www.tianqi556.com/chengyu/86.html 推荐查看天气:http://www.tianqi556.com/chengyu/87.html 推荐查看天气:http://www.tianqi556.com/chengyu/88.html 推荐查看天气:http://www.tianqi556.com/chengyu/89.html 推荐查看天气:http://www.tianqi556.com/chengyu/90.html 推荐查看天气:http://www.tianqi556.com/chengyu/91.html 推荐查看天气:http://www.tianqi556.com/chengyu/92.html 推荐查看天气:http://www.tianqi556.com/chengyu/93.html 推荐查看天气:http://www.tianqi556.com/chengyu/94.html 推荐查看天气:http://www.tianqi556.com/chengyu/95.html 推荐查看天气:http://www.tianqi556.com/chengyu/96.html 推荐查看天气:http://www.tianqi556.com/chengyu/97.html 推荐查看天气:http://www.tianqi556.com/chengyu/98.html 推荐查看天气:http://www.tianqi556.com/chengyu/99.html 推荐查看天气:http://www.tianqi556.com/chengyu/100.html 推荐查看天气:http://www.tianqi556.com/chengyu/101.html 推荐查看天气:http://www.tianqi556.com/chengyu/102.html 推荐查看天气:http://www.tianqi556.com/chengyu/103.html 推荐查看天气:http://www.tianqi556.com/chengyu/104.html 推荐查看天气:http://www.tianqi556.com/chengyu/105.html 推荐查看天气:http://www.tianqi556.com/chengyu/106.html 推荐查看天气:http://www.tianqi556.com/chengyu/107.html 推荐查看天气:http://www.tianqi556.com/chengyu/108.html 推荐查看天气:http://www.tianqi556.com/chengyu/109.html 推荐查看天气:http://www.tianqi556.com/chengyu/110.html 推荐查看天气:http://www.tianqi556.com/chengyu/111.html 推荐查看天气:http://www.tianqi556.com/chengyu/112.html 推荐查看天气:http://www.tianqi556.com/chengyu/113.html 推荐查看天气:http://www.tianqi556.com/chengyu/114.html 推荐查看天气:http://www.tianqi556.com/chengyu/115.html 推荐查看天气:http://www.tianqi556.com/chengyu/116.html 推荐查看天气:http://www.tianqi556.com/chengyu/117.html 推荐查看天气:http://www.tianqi556.com/chengyu/118.html 推荐查看天气:http://www.tianqi556.com/chengyu/119.html 推荐查看天气:http://www.tianqi556.com/chengyu/120.html 推荐查看天气:http://www.tianqi556.com/chengyu/121.html 推荐查看天气:http://www.tianqi556.com/chengyu/122.html 推荐查看天气:http://www.tianqi556.com/chengyu/123.html 推荐查看天气:http://www.tianqi556.com/chengyu/124.html 推荐查看天气:http://www.tianqi556.com/chengyu/125.html 推荐查看天气:http://www.tianqi556.com/chengyu/126.html 推荐查看天气:http://www.tianqi556.com/chengyu/127.html 推荐查看天气:http://www.tianqi556.com/chengyu/128.html 推荐查看天气:http://www.tianqi556.com/chengyu/129.html 推荐查看天气:http://www.tianqi556.com/chengyu/130.html 推荐查看天气:http://www.tianqi556.com/chengyu/131.html 推荐查看天气:http://www.tianqi556.com/chengyu/132.html 推荐查看天气:http://www.tianqi556.com/chengyu/133.html 推荐查看天气:http://www.tianqi556.com/chengyu/134.html 推荐查看天气:http://www.tianqi556.com/chengyu/135.html 推荐查看天气:http://www.tianqi556.com/chengyu/136.html 推荐查看天气:http://www.tianqi556.com/chengyu/137.html 推荐查看天气:http://www.tianqi556.com/chengyu/138.html 推荐查看天气:http://www.tianqi556.com/chengyu/139.html 推荐查看天气:http://www.tianqi556.com/chengyu/140.html 推荐查看天气:http://www.tianqi556.com/chengyu/141.html 推荐查看天气:http://www.tianqi556.com/chengyu/142.html 推荐查看天气:http://www.tianqi556.com/chengyu/143.html 推荐查看天气:http://www.tianqi556.com/chengyu/144.html 推荐查看天气:http://www.tianqi556.com/chengyu/145.html 推荐查看天气:http://www.tianqi556.com/chengyu/146.html 推荐查看天气:http://www.tianqi556.com/chengyu/147.html 推荐查看天气:http://www.tianqi556.com/chengyu/148.html 推荐查看天气:http://www.tianqi556.com/chengyu/149.html 推荐查看天气:http://www.tianqi556.com/chengyu/150.html 推荐查看天气:http://www.tianqi556.com/chengyu/151.html 推荐查看天气:http://www.tianqi556.com/chengyu/152.html 推荐查看天气:http://www.tianqi556.com/chengyu/153.html 推荐查看天气:http://www.tianqi556.com/chengyu/154.html 推荐查看天气:http://www.tianqi556.com/chengyu/155.html 推荐查看天气:http://www.tianqi556.com/chengyu/156.html 推荐查看天气:http://www.tianqi556.com/chengyu/157.html 推荐查看天气:http://www.tianqi556.com/chengyu/158.html 推荐查看天气:http://www.tianqi556.com/chengyu/159.html 推荐查看天气:http://www.tianqi556.com/chengyu/160.html 推荐查看天气:http://www.tianqi556.com/chengyu/161.html 推荐查看天气:http://www.tianqi556.com/chengyu/162.html 推荐查看天气:http://www.tianqi556.com/chengyu/164.html 推荐查看天气:http://www.tianqi556.com/chengyu/165.html 推荐查看天气:http://www.tianqi556.com/chengyu/166.html 推荐查看天气:http://www.tianqi556.com/chengyu/167.html 推荐查看天气:http://www.tianqi556.com/chengyu/168.html 推荐查看天气:http://www.tianqi556.com/chengyu/169.html 推荐查看天气:http://www.tianqi556.com/chengyu/170.html 推荐查看天气:http://www.tianqi556.com/chengyu/171.html 推荐查看天气:http://www.tianqi556.com/chengyu/172.html 推荐查看天气:http://www.tianqi556.com/chengyu/173.html 推荐查看天气:http://www.tianqi556.com/chengyu/174.html 推荐查看天气:http://www.tianqi556.com/chengyu/175.html 推荐查看天气:http://www.tianqi556.com/chengyu/176.html 推荐查看天气:http://www.tianqi556.com/chengyu/177.html 推荐查看天气:http://www.tianqi556.com/chengyu/178.html 推荐查看天气:http://www.tianqi556.com/chengyu/179.html 推荐查看天气:http://www.tianqi556.com/chengyu/180.html 推荐查看天气:http://www.tianqi556.com/chengyu/181.html 推荐查看天气:http://www.tianqi556.com/chengyu/182.html 推荐查看天气:http://www.tianqi556.com/chengyu/183.html 推荐查看天气:http://www.tianqi556.com/chengyu/184.html 推荐查看天气:http://www.tianqi556.com/chengyu/185.html 推荐查看天气:http://www.tianqi556.com/chengyu/186.html 推荐查看天气:http://www.tianqi556.com/chengyu/187.html 推荐查看天气:http://www.tianqi556.com/chengyu/188.html 推荐查看天气:http://www.tianqi556.com/chengyu/189.html 推荐查看天气:http://www.tianqi556.com/chengyu/190.html 推荐查看天气:http://www.tianqi556.com/chengyu/191.html 推荐查看天气:http://www.tianqi556.com/chengyu/192.html 推荐查看天气:http://www.tianqi556.com/chengyu/193.html 推荐查看天气:http://www.tianqi556.com/chengyu/194.html 推荐查看天气:http://www.tianqi556.com/chengyu/195.html 推荐查看天气:http://www.tianqi556.com/chengyu/196.html 推荐查看天气:http://www.tianqi556.com/chengyu/197.html 推荐查看天气:http://www.tianqi556.com/chengyu/198.html 推荐查看天气:http://www.tianqi556.com/chengyu/199.html 推荐查看天气:http://www.tianqi556.com/chengyu/200.html 推荐查看天气:http://www.tianqi556.com/chengyu/201.html 推荐查看天气:http://www.tianqi556.com/chengyu/202.html 推荐查看天气:http://www.tianqi556.com/chengyu/203.html 推荐查看天气:http://www.tianqi556.com/chengyu/204.html 推荐查看天气:http://www.tianqi556.com/chengyu/205.html 推荐查看天气:http://www.tianqi556.com/chengyu/206.html 推荐查看天气:http://www.tianqi556.com/chengyu/207.html 推荐查看天气:http://www.tianqi556.com/chengyu/208.html 推荐查看天气:http://www.tianqi556.com/chengyu/209.html 推荐查看天气:http://www.tianqi556.com/chengyu/210.html 推荐查看天气:http://www.tianqi556.com/chengyu/211.html 推荐查看天气:http://www.tianqi556.com/chengyu/212.html 推荐查看天气:http://www.tianqi556.com/chengyu/213.html 推荐查看天气:http://www.tianqi556.com/chengyu/214.html 推荐查看天气:http://www.tianqi556.com/chengyu/215.html 推荐查看天气:http://www.tianqi556.com/chengyu/216.html 推荐查看天气:http://www.tianqi556.com/chengyu/217.html 推荐查看天气:http://www.tianqi556.com/chengyu/218.html 推荐查看天气:http://www.tianqi556.com/chengyu/219.html 推荐查看天气:http://www.tianqi556.com/chengyu/220.html 推荐查看天气:http://www.tianqi556.com/chengyu/221.html 推荐查看天气:http://www.tianqi556.com/chengyu/222.html 推荐查看天气:http://www.tianqi556.com/chengyu/223.html 推荐查看天气:http://www.tianqi556.com/chengyu/224.html 推荐查看天气:http://www.tianqi556.com/chengyu/225.html 推荐查看天气:http://www.tianqi556.com/chengyu/226.html 推荐查看天气:http://www.tianqi556.com/chengyu/227.html 推荐查看天气:http://www.tianqi556.com/chengyu/228.html 推荐查看天气:http://www.tianqi556.com/chengyu/229.html 推荐查看天气:http://www.tianqi556.com/chengyu/230.html 推荐查看天气:http://www.tianqi556.com/chengyu/231.html 推荐查看天气:http://www.tianqi556.com/chengyu/232.html 推荐查看天气:http://www.tianqi556.com/chengyu/233.html 推荐查看天气:http://www.tianqi556.com/chengyu/234.html 推荐查看天气:http://www.tianqi556.com/chengyu/235.html 推荐查看天气:http://www.tianqi556.com/chengyu/236.html 推荐查看天气:http://www.tianqi556.com/chengyu/237.html 推荐查看天气:http://www.tianqi556.com/chengyu/238.html 推荐查看天气:http://www.tianqi556.com/chengyu/239.html 推荐查看天气:http://www.tianqi556.com/chengyu/240.html 推荐查看天气:http://www.tianqi556.com/chengyu/241.html 推荐查看天气:http://www.tianqi556.com/chengyu/242.html 推荐查看天气:http://www.tianqi556.com/chengyu/243.html 推荐查看天气:http://www.tianqi556.com/chengyu/244.html 推荐查看天气:http://www.tianqi556.com/chengyu/245.html 推荐查看天气:http://www.tianqi556.com/chengyu/246.html 推荐查看天气:http://www.tianqi556.com/chengyu/247.html 推荐查看天气:http://www.tianqi556.com/chengyu/248.html 推荐查看天气:http://www.tianqi556.com/chengyu/249.html 推荐查看天气:http://www.tianqi556.com/chengyu/250.html 推荐查看天气:http://www.tianqi556.com/chengyu/251.html 推荐查看天气:http://www.tianqi556.com/chengyu/252.html 推荐查看天气:http://www.tianqi556.com/chengyu/253.html 推荐查看天气:http://www.tianqi556.com/chengyu/254.html 推荐查看天气:http://www.tianqi556.com/chengyu/255.html 推荐查看天气:http://www.tianqi556.com/chengyu/256.html 推荐查看天气:http://www.tianqi556.com/chengyu/257.html 推荐查看天气:http://www.tianqi556.com/chengyu/258.html 推荐查看天气:http://www.tianqi556.com/chengyu/259.html 推荐查看天气:http://www.tianqi556.com/chengyu/260.html 推荐查看天气:http://www.tianqi556.com/chengyu/261.html 推荐查看天气:http://www.tianqi556.com/chengyu/262.html 推荐查看天气:http://www.tianqi556.com/chengyu/263.html 推荐查看天气:http://www.tianqi556.com/chengyu/264.html 推荐查看天气:http://www.tianqi556.com/chengyu/265.html 推荐查看天气:http://www.tianqi556.com/chengyu/266.html 推荐查看天气:http://www.tianqi556.com/chengyu/267.html 推荐查看天气:http://www.tianqi556.com/chengyu/268.html 推荐查看天气:http://www.tianqi556.com/chengyu/269.html 推荐查看天气:http://www.tianqi556.com/chengyu/270.html 推荐查看天气:http://www.tianqi556.com/chengyu/271.html 推荐查看天气:http://www.tianqi556.com/chengyu/272.html 推荐查看天气:http://www.tianqi556.com/chengyu/273.html 推荐查看天气:http://www.tianqi556.com/chengyu/274.html 推荐查看天气:http://www.tianqi556.com/chengyu/275.html 推荐查看天气:http://www.tianqi556.com/chengyu/276.html 推荐查看天气:http://www.tianqi556.com/chengyu/277.html 推荐查看天气:http://www.tianqi556.com/chengyu/278.html 推荐查看天气:http://www.tianqi556.com/chengyu/279.html 推荐查看天气:http://www.tianqi556.com/chengyu/280.html 推荐查看天气:http://www.tianqi556.com/chengyu/281.html 推荐查看天气:http://www.tianqi556.com/chengyu/282.html 推荐查看天气:http://www.tianqi556.com/chengyu/283.html 推荐查看天气:http://www.tianqi556.com/chengyu/284.html 推荐查看天气:http://www.tianqi556.com/chengyu/285.html

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册