[size=medium]
这段时间在Code Review之余负责一个处理大数据量程序的正常运行。本应该是国庆之前完成的事,但因对程序处理能力的认识不足就拖到了现在。程序由单线程改造为并发,并因此修改当初的设计,后来针对出现的问题做持续的处理及优化。下面列出在完成这个任务时所想到的及问题总结
[b]1. 由使用并发看到的[/b]
在处理大数据量任务时,可以做到的要么提高执行效率,要么并发执行。如果在单线程效率达到瓶颈时,不得不引入并发,并面对随之而来的问题。在我的程序中,多线程删除某个目录下的所有文件,或是多线程往同一文件中写数据,都得考虑同步时的争锁问题。
[list]
[*]线程数量有阈值,并不是越多越好。因应用而定,对共享的争用是需要权衡的。
[*] 设置条件,减少多线程进入同步块的机会。如每条线程执行500条数据,才去检查共享目录的文件。
[*]在频繁出现资源争用的情况时,为不同线程设置不同的sleep时间,错开执行。[/list]
[b]2. 持续优化可以确定的性能瓶颈[/b]
[color=darkred]优化绝对是建立在对已有程序执行效率的分析结果上[/color]。在我的程序中经历的优化有:在单线程性能已无法提高时,选择多线程 --> 解决线程争用共享资源 --> 排除很多无效数据也要下载文件且占据网络资源的情况 --> 解决部分数据依赖于第三方jar包,长时间没有数据返回的问题等。优化之前在可能出现性能问题的地方设置时间点,分析执行时间,以执行时间为依据做代码review。
[b]3. 让程序更聪明些[/b]
在程序运行期,我们希望得到它的执行进度、效率、指出程序瓶颈在哪,更期望程序从主动从问题中恢复,这些要求在程序开发阶段不会考虑太全,需要经过实践的验证,并不断补充。这个问题以前就认识到,但要写出些能上得了台面的东西,还是需要不断积累。
[list]
[*]在网络超时,系统负载高的时候能减缓执行,反之加快执行速度。
[*]如果某些资源在使用一段时间后频繁出现访问延时,就每隔一段时间重启执行程序。
[*]分析每个线程的执行效率,或分析线程数量的较优解
[*]... ...
[/list]
[b]4. 对BufferedWriter的并发访问[/b]
程序中多线程往同一文件中写数据,使用BufferedWriter。之前没有看过BufferedWriter的代码,在访问BufferedWriter之前做同步处理,并在每次append()之后都做flush()操作,造成程序性能损耗严重。在同事的提醒下,修正为每个线程执行N次后再做flush。
看了下BufferedWriter的代码,对上面的两个问题的解释:
1. [color=blue]多线程访问BufferedWriter是否需要同步[/color]
BufferedWriter自带锁,同步对流的访问,所以在外面的同步可要可不要。(append同write方法)[/size]
[size=medium]2. [color=blue]如果append后不做flush,谁来flush[/color]
BufferedWriter自设缓存,且默认大小为8K,大小可修改。[/size]
[size=medium]在往BufferedWriter写数据时,当它发现缓存已满,就将缓存数据写入流中,将新到的数据再次放入缓存中。也就是说如果程序不主动flush的话,当数据值积累到默认缓存大小时,BufferedWriter会自动将缓存数据flush入writer流中。
还有,当BufferedWriter关闭的时候,也会把所有缓存数据自动flush.[/size]
这段时间在Code Review之余负责一个处理大数据量程序的正常运行。本应该是国庆之前完成的事,但因对程序处理能力的认识不足就拖到了现在。程序由单线程改造为并发,并因此修改当初的设计,后来针对出现的问题做持续的处理及优化。下面列出在完成这个任务时所想到的及问题总结
[b]1. 由使用并发看到的[/b]
在处理大数据量任务时,可以做到的要么提高执行效率,要么并发执行。如果在单线程效率达到瓶颈时,不得不引入并发,并面对随之而来的问题。在我的程序中,多线程删除某个目录下的所有文件,或是多线程往同一文件中写数据,都得考虑同步时的争锁问题。
[list]
[*]线程数量有阈值,并不是越多越好。因应用而定,对共享的争用是需要权衡的。
[*] 设置条件,减少多线程进入同步块的机会。如每条线程执行500条数据,才去检查共享目录的文件。
[*]在频繁出现资源争用的情况时,为不同线程设置不同的sleep时间,错开执行。[/list]
[b]2. 持续优化可以确定的性能瓶颈[/b]
[color=darkred]优化绝对是建立在对已有程序执行效率的分析结果上[/color]。在我的程序中经历的优化有:在单线程性能已无法提高时,选择多线程 --> 解决线程争用共享资源 --> 排除很多无效数据也要下载文件且占据网络资源的情况 --> 解决部分数据依赖于第三方jar包,长时间没有数据返回的问题等。优化之前在可能出现性能问题的地方设置时间点,分析执行时间,以执行时间为依据做代码review。
[b]3. 让程序更聪明些[/b]
在程序运行期,我们希望得到它的执行进度、效率、指出程序瓶颈在哪,更期望程序从主动从问题中恢复,这些要求在程序开发阶段不会考虑太全,需要经过实践的验证,并不断补充。这个问题以前就认识到,但要写出些能上得了台面的东西,还是需要不断积累。
[list]
[*]在网络超时,系统负载高的时候能减缓执行,反之加快执行速度。
[*]如果某些资源在使用一段时间后频繁出现访问延时,就每隔一段时间重启执行程序。
[*]分析每个线程的执行效率,或分析线程数量的较优解
[*]... ...
[/list]
[b]4. 对BufferedWriter的并发访问[/b]
程序中多线程往同一文件中写数据,使用BufferedWriter。之前没有看过BufferedWriter的代码,在访问BufferedWriter之前做同步处理,并在每次append()之后都做flush()操作,造成程序性能损耗严重。在同事的提醒下,修正为每个线程执行N次后再做flush。
看了下BufferedWriter的代码,对上面的两个问题的解释:
1. [color=blue]多线程访问BufferedWriter是否需要同步[/color]
BufferedWriter自带锁,同步对流的访问,所以在外面的同步可要可不要。(append同write方法)[/size]
protected Object lock;
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
}
[size=medium]2. [color=blue]如果append后不做flush,谁来flush[/color]
BufferedWriter自设缓存,且默认大小为8K,大小可修改。[/size]
private char cb[];
private static int defaultCharBufferSize = 8192;
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
}
[size=medium]在往BufferedWriter写数据时,当它发现缓存已满,就将缓存数据写入流中,将新到的数据再次放入缓存中。也就是说如果程序不主动flush的话,当数据值积累到默认缓存大小时,BufferedWriter会自动将缓存数据flush入writer流中。
还有,当BufferedWriter关闭的时候,也会把所有缓存数据自动flush.[/size]
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try {
flushBuffer();
} finally {
out.close();
out = null;
cb = null;
}
}
}