Bash 我写的流水线 Shell 脚本 Starved/Deadlocked/Performing 很差
Bash Pipelined Shell scripts I wrote are Starved/Deadlocked/Performing poorly
我已经使用 duff
创建了文件系统中重复文件的报告:
duff ~/Photos > ~/Photos/duplicates.txt
我已经编写了一些 groovy 脚本来将此报告转换为 HTML 页面,我可以在浏览器中查看重复的照片:
cat duplicates.txt | filter_non_existent.groovy | duff_to_json.groovy | json_to_html.groovy > duplicates.html
大约 50% 的时间,它工作得很好,没有任何问题。
有时我的一些脚本没有开始执行,或者 运行 非常慢。为什么会这样,我能做些什么来防止它发生? (为什么 "professionally written" 像 grep 这样的命令行程序没有遇到这个问题?)
更多信息
- 我延迟每个脚本的启动,直到它接收到标准输入(而
没有数据,休眠 2.5 秒)。饥饿更频繁
当睡眠间隔更短时
- 我连接在一起的管道越多,它发生的频率就越高(如果我只是在
cat
之后执行我的脚本之一,我永远不会遇到问题)
这是我的每个脚本正在使用的模板(我使用 groovy 运行time 但坚持使用简单的 java 语法:
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (!br.ready()) {
Thread.sleep(2500L);
}
while (br.ready()) {
String inputLine = br.readLine();
// Do stuff
}
}
根据您提供的有限信息很难说出原因。每次您通过管道连接到 groovy 的另一个实例时,您都会启动一个新的 jvm,它会产生开销并且会给您的系统带来负担。 (检查 java 的默认启动设置。)
另一件事是您的脚本休眠 2.5 秒,然后轮询工作,然后返回休眠 2.5 秒...如果您有 3 个脚本按顺序执行并且一个正在等待另一个的输出,这正在睡觉等。您最多可以等待:
2.5 + 2.5 + 2.5 = 7.5 秒
如果其他脚本必须完成的工作超过一秒,则可能会更长(例如直接在 java 中处理大量字符串)...可能值得您花时间学习使用:bash、grep 等。首先要避免重复发明轮子,其次要使用正确的工具来完成正确的工作。
Groovy 很棒,但是从你正在做的事情来看,你可能可以用 grep -v
过滤东西,对于 duff 到 json,json 到 html,也许写你的适配器直接去 html?听起来你正在做的任何转换文本的工作都可能不是很有效...
为什么要检查流是否准备好?您要做的就是等待数据可用,并在可用时读取它;如果您只是使用普通的潜在阻塞读取,就会发生这种情况。
如果您在没有数据立即可用时立即退出读取循环(您的代码摘录似乎正在这样做),那么您的程序很可能会提前终止,至少在某些时候是这样。如果您只是阅读(可能会阻塞直到数据可用)直到看到 EOF,那么事情应该就可以了。 (这就是 grep 和其他 "professionally written programs" 所做的。)
我已经使用 duff
创建了文件系统中重复文件的报告:
duff ~/Photos > ~/Photos/duplicates.txt
我已经编写了一些 groovy 脚本来将此报告转换为 HTML 页面,我可以在浏览器中查看重复的照片:
cat duplicates.txt | filter_non_existent.groovy | duff_to_json.groovy | json_to_html.groovy > duplicates.html
大约 50% 的时间,它工作得很好,没有任何问题。
有时我的一些脚本没有开始执行,或者 运行 非常慢。为什么会这样,我能做些什么来防止它发生? (为什么 "professionally written" 像 grep 这样的命令行程序没有遇到这个问题?)
更多信息
- 我延迟每个脚本的启动,直到它接收到标准输入(而 没有数据,休眠 2.5 秒)。饥饿更频繁 当睡眠间隔更短时
- 我连接在一起的管道越多,它发生的频率就越高(如果我只是在
cat
之后执行我的脚本之一,我永远不会遇到问题) 这是我的每个脚本正在使用的模板(我使用 groovy 运行time 但坚持使用简单的 java 语法:
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while (!br.ready()) { Thread.sleep(2500L); } while (br.ready()) { String inputLine = br.readLine(); // Do stuff }
}
根据您提供的有限信息很难说出原因。每次您通过管道连接到 groovy 的另一个实例时,您都会启动一个新的 jvm,它会产生开销并且会给您的系统带来负担。 (检查 java 的默认启动设置。)
另一件事是您的脚本休眠 2.5 秒,然后轮询工作,然后返回休眠 2.5 秒...如果您有 3 个脚本按顺序执行并且一个正在等待另一个的输出,这正在睡觉等。您最多可以等待:
2.5 + 2.5 + 2.5 = 7.5 秒
如果其他脚本必须完成的工作超过一秒,则可能会更长(例如直接在 java 中处理大量字符串)...可能值得您花时间学习使用:bash、grep 等。首先要避免重复发明轮子,其次要使用正确的工具来完成正确的工作。
Groovy 很棒,但是从你正在做的事情来看,你可能可以用 grep -v
过滤东西,对于 duff 到 json,json 到 html,也许写你的适配器直接去 html?听起来你正在做的任何转换文本的工作都可能不是很有效...
为什么要检查流是否准备好?您要做的就是等待数据可用,并在可用时读取它;如果您只是使用普通的潜在阻塞读取,就会发生这种情况。
如果您在没有数据立即可用时立即退出读取循环(您的代码摘录似乎正在这样做),那么您的程序很可能会提前终止,至少在某些时候是这样。如果您只是阅读(可能会阻塞直到数据可用)直到看到 EOF,那么事情应该就可以了。 (这就是 grep 和其他 "professionally written programs" 所做的。)