Tar 个文件在单独的进程中使用 open 和 vwait
Tar files in separate process using open and vwait
我有一个内置于 Tcl/Tk 中的 GUI,它有一个可以 tar 向上目录的按钮。
该目录可能非常大,所以我不想在等待时锁定 GUI。
为了实现这一点,我对命令管道和 vwait 使用了 open,但是当 tar 为 运行 时,GUI 仍然没有响应。这是我的代码:
set ::compress_result 0
set pipe [open "|$tar_executable -cf $folder_to_tar.tar $folder_to_tar" r+]
fileevent $pipe readable "set ::compress_result [gets $pipe line]"
vwait ::compress_result
set return_value $::compress_result
unset ::compress_result
close $pipe
为什么这仍然会阻塞 Tcl 事件循环并锁定 GUI?
正在添加
fconfigure $pipe -blocking false
打开管道后会有帮助。
你遇到的关键问题是这一行:
fileevent $pipe readable "set ::compress_result [gets $pipe line]"
这 立即从管道中读取一行 因为 [gets …]
在双引号字符串中。更改为:
fileevent $pipe readable {set ::compress_result [gets $pipe line]}
使事情正常进行,因为它推迟了管道的读取,直到管道变得可读。但是,要做到这一点,它依赖于 pipe
变量是全局的。实际上这样做更好:
fileevent $pipe readable [list apply {pipe {
global compress_result
set compress_result [gets $pipe line]
}} $pipe]
这非常丑陋且难以调试,所以我们 实际上 使用辅助程序:
proc pipedone {pipe} {
global compress_result
set compress_result [gets $pipe line]
}
fileevent $pipe readable [list pipedone $pipe]
此处使用 list
确实“将此作为可运行的脚本引用以备后用”,处理您可能在变量中遇到的任何意外技巧。它知道如何正确引用事物,因此您不必这样做。
在 Tcl 8.6 中,您最好使用协程。
coroutine piperead apply {{tar folder} {
# Open the pipe
set pipe [open |[list $tar -cf $folder.tar $folder] "r"]
# Wait until readable
fileevent $pipe readable [info coroutine]
yield
# Read and close
set return_result [gets $pipe line]
close $pipe
return $return_result
}} $tar_executable $folder_to_tar
我有一个内置于 Tcl/Tk 中的 GUI,它有一个可以 tar 向上目录的按钮。 该目录可能非常大,所以我不想在等待时锁定 GUI。
为了实现这一点,我对命令管道和 vwait 使用了 open,但是当 tar 为 运行 时,GUI 仍然没有响应。这是我的代码:
set ::compress_result 0
set pipe [open "|$tar_executable -cf $folder_to_tar.tar $folder_to_tar" r+]
fileevent $pipe readable "set ::compress_result [gets $pipe line]"
vwait ::compress_result
set return_value $::compress_result
unset ::compress_result
close $pipe
为什么这仍然会阻塞 Tcl 事件循环并锁定 GUI?
正在添加
fconfigure $pipe -blocking false
打开管道后会有帮助。
你遇到的关键问题是这一行:
fileevent $pipe readable "set ::compress_result [gets $pipe line]"
这 立即从管道中读取一行 因为 [gets …]
在双引号字符串中。更改为:
fileevent $pipe readable {set ::compress_result [gets $pipe line]}
使事情正常进行,因为它推迟了管道的读取,直到管道变得可读。但是,要做到这一点,它依赖于 pipe
变量是全局的。实际上这样做更好:
fileevent $pipe readable [list apply {pipe {
global compress_result
set compress_result [gets $pipe line]
}} $pipe]
这非常丑陋且难以调试,所以我们 实际上 使用辅助程序:
proc pipedone {pipe} {
global compress_result
set compress_result [gets $pipe line]
}
fileevent $pipe readable [list pipedone $pipe]
此处使用 list
确实“将此作为可运行的脚本引用以备后用”,处理您可能在变量中遇到的任何意外技巧。它知道如何正确引用事物,因此您不必这样做。
在 Tcl 8.6 中,您最好使用协程。
coroutine piperead apply {{tar folder} {
# Open the pipe
set pipe [open |[list $tar -cf $folder.tar $folder] "r"]
# Wait until readable
fileevent $pipe readable [info coroutine]
yield
# Read and close
set return_result [gets $pipe line]
close $pipe
return $return_result
}} $tar_executable $folder_to_tar