在 Perl 中不关闭目录句柄有什么影响?
我最近继承了别人写的一些代码。
我发现在代码中打开目录进行读取的任何地方,它都不会被关闭,因为原始开发人员存在语法问题 - 他正在使用 close
函数来尝试关闭目录句柄,而不是closedir
函数。
代码是这样的:(
opendir( DIR, $dir ) or die "Cannot open $dir: $!\n";
@files = readdir( DIR );
close( DIR );
这是 Perl 最佳实践(第 208,278 页)关于检查 close
函数的返回的另一个好点。如果 close
的返回code> 在这种情况下被检查,它将因“错误文件号”而失败。)
我已经将其更改为 linedir
,但这让我开始想知道:因为目录句柄从未关闭,长时间保持目录句柄打开有哪些负面影响?
该程序较大(3,500行代码),运行时间较长(5-10分钟),并且该程序的多个实例同时运行。对于上例中的此目录,$dir
对于所有实例都是相同的值。如果该程序的 10 个实例同时运行,则它们都持有同一目录的打开目录句柄 5 分钟或更长时间。我确信 Perl 在程序完成时会自动关闭目录句柄,但最佳实践是尽快关闭它。
对我来说更明显的是,保持文件句柄打开可能会导致问题(尤其是打开用于写入的文件句柄),但是如果不关闭目录句柄会发生什么不好的事情呢?
我问的原因是因为有一个奇怪的情况,该程序试图创建一个文件(在上面 $dir 定义的目录中)。文件名中嵌入了 PID,因此该文件已经存在的可能性较小,但 Perl 无法打开该文件进行写入,因为它表示该文件已经存在。当我们查看目录时,该文件不存在。我想知道该目录上的所有打开目录句柄是否都会导致这样的问题?
我不确定操作系统是否有所不同,但该程序在 AIX 上运行。
提前致谢,周五快乐!
I recently inherited some code that someone else had written.
I discovered that everywhere in the code that a directory was opened for reading, it was never closed because the original developer had a syntax problem - he was using the close
function to try to close a directory handle instead of the closedir
function.
The code was something like this:
opendir( DIR, $dir ) or die "Cannot open $dir: $!\n";
@files = readdir( DIR );
close( DIR );
(Which is another good point that is made in Perl Best Practices (pages 208,278) about checking the return of the close
function. If the return of close
were checked in this case, it would be failing with "Bad file number".)
I've since changed this to closedir
, but it made me start wondering: Since the directory handle was never closed, what are the negative implications to keeping a directory handle opened for a long duration?
This program is larger (3,500 lines of code), runs for a while (5-10 minutes), and multiple instances of this program are running at the same time. In the case of this directory in the example above, $dir
is the same value for all instances. If 10 instances of this program were running at the same time, they all held an open directory handle against the same directory for 5 minutes or longer. I'm sure Perl is closing the directory handle automatically when the program finishes, but best practice says to close it as soon as possible.
It is more obvious to me where leaving file handles open can cause problems (especially for file handles that are open for writing), but what bad things can happen by not closing a directory handle?
The reason I am asking is because there has been an odd circumstance where this program was trying to create a file (in the directory defined by $dir above). The filename had the PID embedded in it, so it is a smaller chance that the file could already be there, but Perl was unable to open the file for writing, because it said it already existed. When we looked in the directory, that file did not exist. I am wondering if all of the open directory handles on this directory could cause such a problem?
I'm not sure if the OS makes a difference, but this program is running on AIX.
Thanks in advance, and happy Friday!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您浪费了一个目录描述符 - 它可能算作一个文件描述符。如果您的程序打开了足够多的目录而耗尽了文件描述符,那么最终会伤害您。否则,它是相当无害的,尽管不太理想。它使系统(和 Perl)保留原本可以释放的资源。
如果目录句柄是局部变量,而不是普通的 DIR 样式名称,则可能会由 Perl 进行清理。请参阅 opendir ,其中显示:
You wasted a directory descriptor - which probably counts as a file descriptor. It would ultimately hurt you if your program opened enough directories to run out of file descriptors. Otherwise, it is pretty harmless, though less than ideal. It makes the system (and Perl) keep resources around which it might otherwise be able to release.
If the directory handle was a local variable, not a plain DIR-style name, you might have Perl cleaning up behind you. See opendir which says:
不会有什么严重的后果。来自内核本身的内存使用量将会有非常轻微的增加,因为内核本身无法释放它内部使用的用于循环目录条目列表的迭代器,并且可能也来自 perl 端。
此外,只要目录的任何描述符仍然打开,数据就无法从文件系统中实际删除。如果某些其他外部进程删除您拥有句柄的目录,它将停止出现在将来的目录列表中,但数据仍然必须保留在磁盘上,并且仍然可以由具有打开句柄的进程访问。例如,这可能会导致磁盘使用量出现奇数。
另请注意,您不必手动关闭所有句柄。当使用词法文件句柄时,一旦对句柄的最后一个引用消失,就会自动关闭:
There won't be any drastic consequences. There will be a very slight increase in memory usage, from the kernel itself, which can't free the iterator it uses internally for looping through the list of directory entries, and probably also from the perl side.
Adittionally, as long as any descriptor to a directory is still open, the data can't be actually deleted from the filesystem. If some other external process would delete the directory you have the handle for, it would stop appearing in future directory listings, but the data would still have to be kept on disk and would still be accessible by the process with the opened handle. That might result in odd numbers in disk usage, for example.
Also note that you don't necessarily have to close all your handles manually. When using lexical filehandles, closing happens automatically as soon as the last reference to the handle goes away:
这是始终使用词法文件(和目录)句柄的教训——词法句柄在超出范围时会自动关闭。
因此,如果 1. 使用旧式 glob 句柄,或者 2. 所有代码都在没有子例程或其他作用域的平面脚本中,那么您只会浪费描述符(正如 Jonathan 所描述的)。使用良好的编程习惯,无意的错误会更少:)
This is a lesson to always use lexical file-(and directory-) handles -- lexical handles are automatically closed when they go out of scope.
So you'd only be wasting descriptors (as Jonathan describes) if 1. you used the old-style glob handle, or 2. all the code is in a flat script with no subroutines or other scoping. Use good programming practices and inadvertent errors will be fewer :)