【发布时间】:2019-08-29 04:28:25
【问题描述】:
我想在现代 nodeJS 工具中有两个并发循环。
一个循环扫描有趣的东西并将它们推送到一个数组中。
第二个循环将数组移出并处理它们。
这个想法是两个循环不会相互阻塞。当第一个循环进行大量扫描但没有找到太多时,第二个循环将能够赶上处理积压。只有当没有积压且没有新数据进来时,处理循环才需要真正等待。
我以多种方式实现了扫描循环。这是容易的部分。 (在这种情况下,我递归地扫描 fs 以查找特定类型的文件。)
对于处理循环,我通过轮询让它工作,但我觉得我应该能够让它与纯异步/等待一起工作。
但我无法理解它。从概念上讲,扫描循环应该履行一个承诺,提醒第二个循环在数组中有东西,或者应该是生成每个新值而不是使用数组的生成器。
但是我看不出如何一遍又一遍地做一个承诺,或者直接等待数组活动,或者作为一个生成器来做而不导致两个循环之间的阻塞。
我一定是想多了!我错过了什么?
通过轮询工作的代码,带有可能属于异步/等待实现的注释位:
"use strict";
const { basename, join } = require('path')
const { promisify } = require('util')
const fs = require('fs')
const readdir = promisify(fs.readdir)
const lstat = promisify(fs.lstat)
async function* scanpaths(paths) {
for (const path of paths) {
yield* scanonepath(path)
}
}
async function* scanonepath(path) {
try {
const s = await lstat(path)
if (s.isDirectory()) {
for (const entry of await readdir(path)) {
yield* scanonepath(join(path, entry))
}
} else if (/\.[mM][pP]3$/.test(path)) {
yield { pathname:path, basename:basename(path), stat:s }
}
} catch (e) {
// special file, deleted file, etc
}
}
async function* checkqueue(buf) {
if (buf.length) {
yield buf.shift()
} else {
// TODO await something to arrive in the buf - HOW?
}
}
async function processmp3(fullname, name, stat) {
try {
console.log(fullname)
// TODO tricky processing goes here
} catch (e) {
console.log(name, e)
}
}
(async () => {
let int = null
let globaldone = false
let globalprocessing = []
let buf = []
async function poll() {
if (buf.length) {
let clone = Array.from(buf)
buf.length = 0 // NOT buf = [] as that doesn't change other refs to buf
for (let e of clone) {
globalprocessing.push(processmp3(e.pathname, e.basename, e.stat))
}
}
if (globaldone) {
await Promise.all(globalprocessing)
console.warn("*** finished processing")
} else {
setTimeout(poll, 125)
}
}
// start polling for scanned files ready to process
console.log("** start polling")
setTimeout(poll, 0)
//console.log("** start scanning")
//await enqueue(buf)
globaldone = true
console.warn("*** finished scanning")
})()
// TODO how?
async function enqueue(buf) {
// start scanning by iterating over our generator which does the recursive directory stuff
for await (const file of scanpaths(process.argv.slice(2))) {
buf.push(file)
// TODO resolve a promise to notify dequeue? or also yield this file
}
}
【问题讨论】:
-
I must be overthinking it!- 是的,想太多,编码不够What am I missing?... 代码? -
我可以把整个代码都放进去。我通常会发现这样一堵文字墙会在这里忽略一个问题......
-
没有代码也是如此
-
为什么不每次向数组添加一些东西时添加一个异步操作?那时每个过程都是分开的。
-
@JaromandaX:代码就是这样。轮询按原样工作。一些令人困惑的评论区域是一些可能的工作方式而无需轮询可能会或现在可能会去。
标签: javascript concurrency promise async-await generator