【问题标题】:file writing operation in tcl takes lot of timetcl中的文件写入操作需要很多时间
【发布时间】:2016-09-01 03:41:03
【问题描述】:
set filePointer [open "fileName" "r"]
set fileWritePointer [open "fileNameWrite" "w"]
set lines [split [read $filePointer] "\n"]
close $filePointer
set length [llength $lines]
for {set i 0} {$i<$length} {incr i} {
        if {[regexp "Matching1" $line]} {
           puts $fileWritePointer $line
        }
        if {[regexp "Matching" $line]} {
           puts $fileWritePointer $line
        }
}
close $fileWritePointer

我一次读取文件的所有行,并用换行符分割它,并在 for 循环内一次读取每一行。

在使用正则表达式对行进行一些语法检查后,我使用以下语法仅将选定的行转储到新文件中。

puts $filePointer $line

我的文件有大约 200 万行代码。 像这样的许多正则表达式匹配大约出现在 1.5 左右。

【问题讨论】:

  • 您最好逐行阅读。 while {[gets $fp line]!=-1} { # process here; } close $fp
  • @Dinesh:我曾尝试在不使用列表的情况下逐行阅读,但与这种方法相比需要很多时间。 [stackoverflow.com/questions/31139120/…
  • 我们需要更多细节。例如,您的意思是您的文件有 200 万行?在哪个操作系统上?需要多少时间?读取部分慢,写入部分还是两者兼而有之?和tcl版本。
  • @ravi507 您链接的帖子说您必须关心内存。你刚刚说你的文件有 200 万行,但没有关于这些行有多长。在您的情况下,您必须考虑内存中包含 200 万个元素的列表。也许您可以尝试检查程序内存打印。
  • @MarioAlexandroSantini :我使用的是 CentOS 版本 5.6(最终版),tcl 版本是 8.5。读部分比写部分快。

标签: tcl


【解决方案1】:

在不知道为什么的情况下,代码很慢(或者您究竟使用基线来衡量什么),很难确定如何加速它。不过,您可以尝试切换到流式处理:

set fin [open "fileName"]
set fout [open "fileNameWrite" "w"]
while {[gets $fin line] >= 0} {
    if {[regexp "Matching1" $line]} {
        puts $fout $line
    }
    if {[regexp "Matching" $line]} {
        puts $fout $line
    }
}
close $fout
close $fin

您应该确保您的正则表达式在处理期间是常量值,以避免为每一行重新编译它们(这会非常慢!)尽管这些常量值可以 存储在变量中,只要使用这些变量而不添加任何东西:

set RE1 "Matching1"
set RE2 "Matching"
# Note: these variables are NOT assigned to below! They are just used!

set fin [open "fileName"]
set fout [open "fileNameWrite" "w"]
while {[gets $fin line] >= 0} {
    # Added “--” to make sure that the REs are never interpreted as anything else
    if {[regexp -- $RE1 $line]} {
        puts $fout $line
    }
    if {[regexp -- $RE2 $line]} {
        puts $fout $line
    }
}
close $fout
close $fin

您还可以通过选择正确的编码、将所有这些代码放在一个过程中等来获得额外的速度。如上所述,如果不知道为什么代码实际上很慢,很难确定什么是最好的尝试,并且这部分取决于运行它的系统。

【讨论】:

  • 另外,如果你想要速度,不要使用seek;它强制缓冲区刷新。
【解决方案2】:

你真的需要正则表达式匹配吗?字符串匹配可能会更快。

是否可以针对同一行进行多个匹配,在这种情况下,您真的需要为每个匹配编写一次该行吗?如果没有,您可以在成功后跳过其余的匹配尝试来加快速度:

if {[regexp -- $RE1 $line]} {
    puts $fout $line
} elseif {[regexp -- $RE2 $line]} {
    puts $fout $line
} elseif { ... } {

if {
    [regexp -- $RE1 $line] ||
    [regexp -- $RE2 $line] ||
    ...
} then {
    puts $fout $line
}

switch -regexp -- $line \
    $RE1 - \
    $RE2 - \
    ...  - \
    default {
        puts $fout $line
    }

【讨论】:

  • 谢谢!!!通过使用 elseif 条件而不是 if ,执行时间开始减少。
猜你喜欢
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-22
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
相关资源
最近更新 更多