Ruby: puts != print + “\n”
今天看到railschina论坛上一篇贴子在讨论在Ruby中,puts str是不是等于print str + “\n”。因为一位同学做了实验,在irb中,在多线程环境下使用puts似乎有问题,有的时候字符串和换行的顺序会乱,而用print就没有问题,所以得出结论,认为puts是不等于print + “\n”的。又有人提出质疑,因为做了另外的实验,在非irb环境下,puts和print都没有问题,所以认为多线程问题只是主观臆测,有可能是irb的问题。甚至还有人写信给Dave,结果Dave也没有给出明确的答复~
正好手头上有Ruby的源代码,所以翻出来看了一下,在io.c中,明确的写明了Ruby中ios.puts方法的实现:
VALUE
rb_io_puts(argc, argv, out)
int argc;
VALUE *argv;
VALUE out;
{
int i;
VALUE line;
/* if no argument given, print newline. */
if (argc == 0) {
rb_io_write(out, rb_default_rs);
return Qnil;
}
for (i=0; i<argc; i++) {
if (NIL_P(argv[i])) {
line = rb_str_new2("nil");
}
else {
line = rb_check_array_type(argv[i]);
if (!NIL_P(line)) {
rb_protect_inspect(io_puts_ary, line, out);
continue;
}
line = rb_obj_as_string(argv[i]);
}
rb_io_write(out, line);
if (RSTRING(line)->len == 0 ||
RSTRING(line)->ptr[RSTRING(line)->len-1] != '\n') {
rb_io_write(out, rb_default_rs);
}
}
return Qnil;
}
可以看到27行和30行就是分别向流中写我们传入的string和”\n”的代码,所以puts确实是存在潜在的多线程问题的。而对于print str + “\n”这种方式,因为ruby会先把str和”\n”构造为一个新的string,然后再传给print函数,所以是没有这种问题的。总结:在Ruby中,puts != print + “\n”
另外,如果用print(str1, str2)这种形式,同样会有多线程问题。因为在Ruby中,print的实现是,一个一个参数分别写入流,而不是先将参数合并,再一次写入。(合并参数会占用额外的内存,多次IO又会消耗时间,不知道最初Ruby是如何权衡这个的~)
发表评论
| Trackback








