Node.js 如果nodejs使用非阻塞IO,如何实现fs.readFileSync?
我在中看到很多同步函数。例如Node.js 如果nodejs使用非阻塞IO,如何实现fs.readFileSync?,node.js,blocking,nonblocking,Node.js,Blocking,Nonblocking,我在中看到很多同步函数。例如fs.readFileSync(文件名,[options]) 如果节点具有异步/非阻塞IO且没有睡眠方法,那么这些函数是如何实现的(为什么实现的)?我可以使用相同的机制来实现其他同步函数吗 fs.readFileSync() 这真的只是一个包装 fs.readSync() 功能。所以问题是,与fs.read()相比,fs.readSync()是如何实现的。如果您查看这两个函数的实现,它们都利用了bindings模块。在这种情况下,初始化为 var binding
fs.readFileSync(文件名,[options])
如果节点具有异步/非阻塞IO且没有睡眠方法,那么这些函数是如何实现的(为什么实现的)?我可以使用相同的机制来实现其他同步函数吗
fs.readFileSync()
这真的只是一个包装
fs.readSync()
功能。所以问题是,与fs.read()相比,fs.readSync()是如何实现的。如果您查看这两个函数的实现,它们都利用了bindings模块。在这种情况下,初始化为
var binding = process.binding('fs').
电话是
binding.read(fd, buffer, offset, length, position, wrapper);//async
var r = binding.read(fd, buffer, offset, length, position);//sync
分别。一旦进入“绑定”模块,我们就进入了v8,node######.cc land。绑定(“fs”)的实现可以在node_file.cc中的节点存储库代码中找到。节点引擎提供C++调用的重载,一个调用回调,一个不重载。node_file.cc代码利用了req_wrap类。这是v8发动机的包装。在node_file.cc中,我们可以看到:
#define ASYNC_CALL(func, callback, ...) \
FSReqWrap* req_wrap = new FSReqWrap(#func); \
int r = uv_fs_##func(uv_default_loop(), &req_wrap->req_, \
__VA_ARGS__, After); \
req_wrap->object_->Set(oncomplete_sym, callback); \
req_wrap->Dispatched(); \
if (r < 0) { \
uv_fs_t* req = &req_wrap->req_; \
req->result = r; \
req->path = NULL; \
req->errorno = uv_last_error(uv_default_loop()).code; \
After(req); \
} \
return scope.Close(req_wrap->object_);
#define SYNC_CALL(func, path, ...) \
fs_req_wrap req_wrap; \
int result = uv_fs_##func(uv_default_loop(), &req_wrap.req, __VA_ARGS__, NULL); \
if (result < 0) { \
int code = uv_last_error(uv_default_loop()).code; \
return ThrowException(UVException(code, #func, "", path)); \
}
#定义异步调用(func、回调等)\
FSReqWrap*req_wrap=新的FSReqWrap(#func)\
int r=uv_fs_##func(uv_default_loop(),&req_wrap->req#\
__(a)在(a)之后\
请求换行->对象->设置(oncomplete\u sym,回调)\
请求包装->已调度()\
如果(r<0){\
uv_fs_t*req=&req_wrap->req\
请求->结果=r\
req->path=NULL\
req->errorno=uv\U last\U错误(uv\U default\U loop())。代码\
之后(req)\
} \
返回范围。关闭(请求包装->对象包装);
#定义同步调用(函数、路径,…)\
fs_REQU_wrap REQU_wrap\
int result=uv_fs_35;#func(uv_default_loop(),&req_wrap.req,u VA_ARGS_35;,NULL)\
如果(结果<0){\
int code=uv\u last\u错误(uv\u default\u loop())。代码\
返回throweexception(UVException(code,#func,“,path))\
}
请注意,SYNC_调用使用不同的req wrap。以下是异步方法的相关req_wrap构造函数的代码,可在req_wrap.h中找到
ReqWrap() {
v8::HandleScope scope;
object_ = v8::Persistent<v8::Object>::New(v8::Object::New());
v8::Local<v8::Value> domain = v8::Context::GetCurrent()
->Global()
->Get(process_symbol)
->ToObject()
->Get(domain_symbol);
if (!domain->IsUndefined()) {
// fprintf(stderr, "setting domain on ReqWrap\n");
object_->Set(domain_symbol, domain);
}
ngx_queue_insert_tail(&req_wrap_queue, &req_wrap_queue_);
}
ReqWrap(){
v8:手镜范围;
对象=v8::Persistent::New(v8::object::New());
v8::Local domain=v8::Context::GetCurrent()
->全局()
->获取(进程\符号)
->ToObject()
->Get(域\符号);
如果(!domain->IsUndefined()){
//fprintf(stderr,“在ReqWrap上设置域\n”);
对象\设置(域\符号,域);
}
ngx_队列_插入_尾(&req_包装_队列,&req_包装_队列);
}
请注意,此函数正在创建一个新的v8范围对象来处理此事件的运行。这就是异步内容的异步部分发生的地方。v8引擎启动了一个新的javascript解释环境来单独处理这个特定的调用。简言之,如果不构建/修改自己的node版本,就无法实现自己的异步/同步版本的调用,就像node那样。也就是说,异步实际上只适用于I/O操作。也许你应该描述一下为什么你认为你需要事情更加同步。通常,如果您认为node不支持您想做的事情,那么您就是没有充分利用回调机制
所述,如果需要异步行为,可以考虑使用事件节点模块来实现自己的事件处理程序。如果你需要同步地做一些事情,你可以考虑本机扩展,但是,我强烈建议不要这样做。考虑如何在异步事件循环中工作以获得这样做所需做的事情。接受这种思维方式,或者改用另一种语言
强迫一种语言以一种它不希望的方式来处理事情,这是编写糟糕代码的一种很好的方法。非常彻底的答案<代码>强制一种语言以一种它不希望的方式处理事情——这是一种有趣的措辞。这不正是nodeJS人使用fs.readFileSync所做的吗?它为什么存在?也许节点中毕竟有同步调用的空间?Stackoverflow。。。永远不知道当你给某人一个他们还没有准备好使用的工具时。最后一句话(为什么在一堆事实中挑一个固执己见的句子?)。。。嘿,我不支持尝试修改节点的想法!但如果你必须这样做,你就是这样做的。你可能是对的,可能有更多的同步调用空间,让开发人员决定使用哪个,但是现在,Node的开发人员已经决定情况并非如此,这正是我的观点。根据你的问题,同步FS方法的存在有两个原因。答:作为初始化步骤的一部分,收集配置信息是一种相对常见的需要,而且同步进行比较简单。B:在某些情况下,一系列的同步磁盘请求实际上比用一堆它不准备处理的异步请求来淹没磁盘更有效。服务器IO(DDOS攻击)也是如此,这只是一个非常难以创建的环境(比如10000x)。然而,单个进程很容易使磁盘驱动器过载,并以指数方式降低自身速度。参考您的句子
asynchronous实际上只适用于I/O操作