node.js中存在mmap模块:https://github.com/bnoordhuis/node-mmap/
正如作者Ben Noordhuis所指出的,访问映射内存可能会阻塞,这就是为什么他不再推荐它并停止使用它的原因。
所以我想知道如何为node.js设计一个非阻塞内存映射模块?穿线,纤维,?
显然,这附近提出了一个问题,如果线程在node.js只是发生在其他地方,而不是请求处理程序。
当谈到以非阻塞方式实现某些本机功能时,首先要看的是libuv。它是node的核心模块与底层平台的接口。特别有趣的是工作队列API。
如果我们快速查看一下node-mmap的源代码,我们会发现它实际上非常简单。它调用mmap
并返回一个包含映射内存区域的节点Buffer
。
从这个Buffer
读取是导致操作系统执行I/O的原因。因为这必然会发生在JS线程上,我们最终会用磁盘I/o阻塞JS线程。
不是返回允许JS直接访问映射内存的Buffer
,而是应该用c++编写一个包装器类,通过工作队列封送读取和写入。通过这种方式,磁盘I/O将发生在一个单独的线程上。
在JS中,你可以这样使用它:
fs.open('/path/to/file', 'r', function(err, fd) {
fs.fstat(fd, function(err, stats) {
var mapped = mmap.map(stats.size, mmap.PROT_READ, mmap.MAP_SHARED, fd, 0);
mapped.read(start, len, function(err, data) {
// ...
});
});
});
在C语言中,read
函数将创建libuv工作请求并将其放入工作队列中。然后,C工作函数将读取映射的内存范围(基于调用者的规范),这可能会导致磁盘I/O,但这是安全的,因为它发生在单独的线程上。
接下来发生的事情很有趣。安全的方法是工作线程从映射的内存中alloc
一个新的内存块和memcpy
。然后worker传递一个指向副本的指针,C回调将其封装在一个Buffer
中返回给JS-land。
您也可以尝试读取范围(以便在工作线程上发生任何必要的I/O),但实际上不对数据做任何事情,然后让C回调简单地将映射的内存范围包装在Buffer
中。理论上,工作程序读取的文件部分将留在RAM中,因此对映射内存部分的访问不会阻塞。然而,老实说,我对映射内存的了解还不够多,无法判断这是否会让你吃苦头。
最后,我怀疑这是否会比node的常规fs
方法提供任何额外的性能。我只会在需要使用mmap
的时候才会这么做。