Redian新闻
>
多线程真头疼,但也挺有趣
avatar
多线程真头疼,但也挺有趣# Java - 爪哇娇娃
r*r
1
有点点长啊。
有一个 tool, 以前处理的数据比较少,所以速度,时间都不成问题。但现在需要处理
的数据增大,速度问题就突出了。费了好大一番力气,总算弄通了,一次处理的时间由
原来的 24 个小时,减小为 3 个小时。
第一次弄多线程,很费劲。但弄通了(只是这个小 task 弄通了,并非多线程弄通了)
,又觉得很有意思,小有成就感。分享一下,希望对 beginner 有帮助,也希望有经验
的多指教。其中有些地方,还没有完全明白,正在学习-ing。
程序其实也简单,就是在单机上运行的一个程序。过去单线程的,即使在多 core 的机
器上运行,也只能利用处理器的少部分能力。现在就是要改为多线程,多核处理。
数据存在 10 个文本文件中,每个大约 40M.程序从每个文件逐行读取,逐行处理,很
多信息被保存到不同的数据结构中。最后输出处理报告,中间还要将部分处理信息输出
到一个 XML 文件中。
经过一番 google search 和研究,所做的改动包括:
1) 将原来的逐行读取,逐行处理,改为先将每个文件的所有行读到一个新建的
DataStore 中,这个结构比较简单。就是保持原来的每行文本信息,以及行号,和
getter, setter 等。每个都加上 synchronized
class DataStore{
}
2) 建立一个 thread pool,并将这个 DataStore 对象传到这个 pool 中。
ExecutorService executor = Executors.newFixedThreadPool(count);
for (int i = 0; i < count; i++) {
Runnable dataThread = new DataThread(dataStore,
"Thread " + i);
executor.execute(dataThread);
}
3) DataThread 的 run(),基本上就运行原来的代码,原来是从文件读取每一行,现在
变为从 dataStore 中逐行取得文本进行处理。
4)原来逐行处理,逐行输出部分信息到一个 XML 文件中,原来的记录顺序需要保持。
现在由于多线程异步处理,直接输出无法保证顺序。就先把这部分信息存储到一个新建
的 map 中,保存记录 ID -> data 的映射。当一个文件处理完了,才最后按 ID 从
map 有序输出到 XML 中。
5)其他很多信息需要计算,排序和保存。过去用的都是无保护的 Map, List, Set,以
及原始的 int. 后来在需要的地方,对这些数据存储对象都加上锁。比如:
synchronized(dataMap){
dataMap.remove(id);
}
其他需要帮助处理结果的 private static 方法,也都加上了 synchronized.
6)很多 int 型的计算 (i.e. itemCounts++), 都从 int 变成了 AtomicInteger.
基本上就这样。下面是几点体会。
1)为了测试多线程下无线程保护时可能出现的问题。开始我故意对所有的那些 map,
list 和 set 都用原来的,无任何保护。一运行,果然,上面那个 dataMap 马上出错
。数据处理完后,抛出一个 RuntimeException, 提示数据状态 inconsistent.
2) 遇到一个困难。就是在 local 机器上测试时,虽然发现速度明显提高,50% 左右,
但是通过 OS 的 performance monitor 观察时,发现内存使用逐渐小幅增加,当数据
处理越 2/3 后,内存所剩已无几,而 cpu 也马上从多 core,变为过去的单 core.但
机器并没有停下来,而是按单 core 的速度,处理完剩下的 1/3, memory 此期间全负
荷运转。
多线程的程序,怎么自动变成了单线程?memory usage 为什么增加? memory 增加
,其实预见到了,由于上面提到的改动 4),原来不保存,现在逐渐保存到一个 map 中
,所以消耗内存。没想到影响这么大,可能是记录比较多的缘故。再联系到 CPU 的使
用,原来当 memory 快耗尽时,OS or JVM 能够探测到,就自动 switch 到 single
core, 以保证程序继续运行。这里,还挺 smart 哈。
后来,就为解决这个问题,费力了。数据再大一点,可能就会死机了。等一个文件处
理完,存储到 map 中的方案不行。还得在处理数据的同时,想办法输出,不保存,或
少保存信息到 map 中。可是,异步处理,如何保持输出顺序呢?
try 了很多次,又 search 了很多,最后找到办法了。在原来 10 个 thread 的基础
上,再加一个专用的 thread, 在其他 10 thread 处理 dataStore 并存储到
resultMap 的同时,负责 concurrently 从这个 map 中输出信息到 XML 文件中;每当
一条信息输出完,就立刻从 map 中删除记录。这样,这个 map 的 size 一直会维持在
非常小的水平。如何控制顺序呢?就取一个循环变量。
int i =0;
do(
{
DataRecord record = resultMap.get(i);
if( record != null ){
// 1. output
// 2. resultMap.remove(i)
// i++
}else{
Thread.sleep(1000);
}
}while(i觉得这段小程序真是体现了 multithread 的精髓。多人同时干一件事多或多件事,
并相互协调,保证很好的完成任务。主要的 10 个线程处理耗资源和时间的主任务,另
一个 thread 负责简单的输出;当它空闲无任务可做时,就通过睡觉 (sleep),稍事休
息,又继续工作,直到结束。fun!
3) 最后,又经过了一点优化吧。上面提到需要存取多个 map, list 和 set 时,都用
synchronized block 加锁。这样一来,有很多地方都需要这样,看上去不好。后来就
做了改动:
Map -> ConcurrentHashMap
List -> ConcurrentSkipListMap
只有一个 ArrayList 还是用 synchronized 加锁,因为不确定改为
CopyOnWriteArrayList 是否合适,还在研究!
最终,速度又从 50% 进一步减少为原来的 1/8,内存问题也得到了解决。发现速度的
提高,基本上与 thread pool 中线程数量成比例的增加。当然,thread 的数量应该小
于所在机器 core 的数量?
使用 Executors.newFixedThreadPool(count) 这张方式,很容易测试单线程和多线的
区别,所需要改的就是改变那个 count 变量的值,很方便。
最后提一下,第一次在 debugger 里调试多线程,感觉难多了!
avatar
n*1
2
一直想学多线程,但是缺少任务驱动
可惜你的程序不能分享出来
avatar
p*2
3
你搞的这么复杂不如直接用AKKA。
avatar
e*t
4
This is a ver good article for beginners.
it clearly shows the learning curve and the difference bewteen single-thread
ed programs and multi-threaded programs.
You are on the right track. +U+U

【在 r******r 的大作中提到】
: 有点点长啊。
: 有一个 tool, 以前处理的数据比较少,所以速度,时间都不成问题。但现在需要处理
: 的数据增大,速度问题就突出了。费了好大一番力气,总算弄通了,一次处理的时间由
: 原来的 24 个小时,减小为 3 个小时。
: 第一次弄多线程,很费劲。但弄通了(只是这个小 task 弄通了,并非多线程弄通了)
: ,又觉得很有意思,小有成就感。分享一下,希望对 beginner 有帮助,也希望有经验
: 的多指教。其中有些地方,还没有完全明白,正在学习-ing。
: 程序其实也简单,就是在单机上运行的一个程序。过去单线程的,即使在多 core 的机
: 器上运行,也只能利用处理器的少部分能力。现在就是要改为多线程,多核处理。
: 数据存在 10 个文本文件中,每个大约 40M.程序从每个文件逐行读取,逐行处理,很

avatar
e*t
5
I think the key here is to understand the complexity instead of using some f
ramework to hide them.
When you try to learn something, you learn how it works. But in real world,
if you need a quick solution for a problem, I agree, you don't want to reinv
ent the wheel.

【在 p*****2 的大作中提到】
: 你搞的这么复杂不如直接用AKKA。
avatar
p*2
6

f
,
reinv
Java的threading model是不是在学校都学过了?

【在 e*****t 的大作中提到】
: I think the key here is to understand the complexity instead of using some f
: ramework to hide them.
: When you try to learn something, you learn how it works. But in real world,
: if you need a quick solution for a problem, I agree, you don't want to reinv
: ent the wheel.

avatar
r*r
7
多线程就是一个机制,包括对一些数据结构的选择和利用,它本身并不增加很多代码。
比如,你可以练习一下我上面遇到的其中一个问题:
* Given an ArrayList to store 100000 integers from 1 ... 100000.In
a single threaded program, you will be able to easily output in the order of
the array list.
Now change it to a 10 thread program, how to achieve the same effect?


【在 n******1 的大作中提到】
: 一直想学多线程,但是缺少任务驱动
: 可惜你的程序不能分享出来

avatar
r*r
8
刚 google 了一下,这个用的广泛吗?
我们公司 backend 代码中涉及到多线程的,都是直接使用 Java 本身提供的支持。
It's good to know this AKKA though.

【在 p*****2 的大作中提到】
: 你搞的这么复杂不如直接用AKKA。
avatar
r*r
9
Thanks.
Will share more when I have more findings or insights from practical
problems.

thread

【在 e*****t 的大作中提到】
: This is a ver good article for beginners.
: it clearly shows the learning curve and the difference bewteen single-thread
: ed programs and multi-threaded programs.
: You are on the right track. +U+U

avatar
r*r
10
Now it's time to put learning points into a practical problem.
Only reading Java API is insufficient for me to solve the problem, even
though it's not big enough.

【在 p*****2 的大作中提到】
:
: f
: ,
: reinv
: Java的threading model是不是在学校都学过了?

avatar
p*2
11

In
of
这个问题为什么要用multi thread来解决呢?

【在 r******r 的大作中提到】
: 多线程就是一个机制,包括对一些数据结构的选择和利用,它本身并不增加很多代码。
: 比如,你可以练习一下我上面遇到的其中一个问题:
: * Given an ArrayList to store 100000 integers from 1 ... 100000.In
: a single threaded program, you will be able to easily output in the order of
: the array list.
: Now change it to a 10 thread program, how to achieve the same effect?
:

avatar
p*2
12

不少人认为Java multi threading的代码只是理论上存在bug free,并且并发性不高。
不过具体怎么样我也不清楚,我也不是搞Java的。个人感觉问题复杂起来确实容易出
bug。

【在 r******r 的大作中提到】
: 刚 google 了一下,这个用的广泛吗?
: 我们公司 backend 代码中涉及到多线程的,都是直接使用 Java 本身提供的支持。
: It's good to know this AKKA though.

avatar
r*r
13
这个简单例子中,是用不着。可是,他不是说想练习吗? 模拟一下而已

【在 p*****2 的大作中提到】
:
: 不少人认为Java multi threading的代码只是理论上存在bug free,并且并发性不高。
: 不过具体怎么样我也不清楚,我也不是搞Java的。个人感觉问题复杂起来确实容易出
: bug。

avatar
c*m
14
一些建议:
1. DataStore if I understand correctly is a read only object, 完全没必要
synchronized。做成immutable就行了
2. CPU没有那么smart, 会知道JVM快用完memory而只用一个thread。最可能的是设计有
问题。
3. 任何有non-significant load的地方,都不要简单地用synchronized keyword,用
concurrent collection效率更高。
4. thread 数量完全可以超过core的数量,只要你的程序不是完全CPU bound or IO
bound, 哪怕是单核用multi-threading也有好处。
5. 如果需要Map自动清理entry, 可以考虑WeakReference。用一个thread来确保内存不
增长,没有可预期性,在Production环境太危险。
6. 最后,我最不理解的地方就是,什么数据处理,400M要用3小时,甚至24小时? 我
们的计算,用单核CPU,包括大量的Database IO和大量的数学运算,处理20G数据只需
要20分钟。这还是没怎么优化过的。处理400M data,连IO算上,也用不了一分钟吧,
强烈感觉设计有问题。不妨把你的算法贴出来看看。
avatar
j*f
15

我也觉得用
do
sleep(1000)
}while(i这样不够好,应该直接用while true循环,

【在 c*m 的大作中提到】
: 一些建议:
: 1. DataStore if I understand correctly is a read only object, 完全没必要
: synchronized。做成immutable就行了
: 2. CPU没有那么smart, 会知道JVM快用完memory而只用一个thread。最可能的是设计有
: 问题。
: 3. 任何有non-significant load的地方,都不要简单地用synchronized keyword,用
: concurrent collection效率更高。
: 4. thread 数量完全可以超过core的数量,只要你的程序不是完全CPU bound or IO
: bound, 哪怕是单核用multi-threading也有好处。
: 5. 如果需要Map自动清理entry, 可以考虑WeakReference。用一个thread来确保内存不

avatar
b*e
16
Datastore 用 ArrayBlockingQueue 就可以了,设定好size.
avatar
l*s
17
mark, enlightening!
avatar
z*3
18
一旦会出现某一类型的任务不能在短时间内完成
就需要上多线程
楼主的这种系统应该考虑用hadoop
avatar
z*y
19
multi-threading is just another way to express your code
used in right way, it may offer more readability
but it is nothing as fancy as you think
and for programs shooting performance and scalability
it is not a favorable toy
not to mention it is hard to debug
avatar
p*2
20

我看起来也像是应该考虑mapreduce

【在 z*******3 的大作中提到】
: 一旦会出现某一类型的任务不能在短时间内完成
: 就需要上多线程
: 楼主的这种系统应该考虑用hadoop

avatar
T*U
21
fortran并行语言都出来二十多年了,怎么java还在玩多线程

【在 r******r 的大作中提到】
: 有点点长啊。
: 有一个 tool, 以前处理的数据比较少,所以速度,时间都不成问题。但现在需要处理
: 的数据增大,速度问题就突出了。费了好大一番力气,总算弄通了,一次处理的时间由
: 原来的 24 个小时,减小为 3 个小时。
: 第一次弄多线程,很费劲。但弄通了(只是这个小 task 弄通了,并非多线程弄通了)
: ,又觉得很有意思,小有成就感。分享一下,希望对 beginner 有帮助,也希望有经验
: 的多指教。其中有些地方,还没有完全明白,正在学习-ing。
: 程序其实也简单,就是在单机上运行的一个程序。过去单线程的,即使在多 core 的机
: 器上运行,也只能利用处理器的少部分能力。现在就是要改为多线程,多核处理。
: 数据存在 10 个文本文件中,每个大约 40M.程序从每个文件逐行读取,逐行处理,很

avatar
p*2
22

这个问题问的好。呵呵。

【在 T*U 的大作中提到】
: fortran并行语言都出来二十多年了,怎么java还在玩多线程
avatar
k*g
23

There is a concept called Deterministic Parallelism which is much less
likely to have bugs.
Task parallelism and Data parallelism are two examples.
The key idea is to focus on accurate declaration of data dependency to the
scheduler. Namely, to tell the scheduling system what input data items are
needed before a task and start; what data items are modified; what outputs
are generated; and the follow-up tasks that will use the output.
The traditional approach of using synchronization primitives (locks, etc) as
the sole means of "telling" the scheduling environment is the biggest
source of bugs. Instead, each task should give all dependency information to
the scheduler up front.
Task parallelism and Data parallelism are supported by most modern
concurrency frameworks written in the last 5 years or so.

【在 p*****2 的大作中提到】
:
: 这个问题问的好。呵呵。

avatar
p*2
24

as
to
Task parallelism and Data parallelism are supported by most modern
concurrency frameworks written in the last 5 years or so.
Can you give some example frameworks?

【在 k**********g 的大作中提到】
:
: There is a concept called Deterministic Parallelism which is much less
: likely to have bugs.
: Task parallelism and Data parallelism are two examples.
: The key idea is to focus on accurate declaration of data dependency to the
: scheduler. Namely, to tell the scheduling system what input data items are
: needed before a task and start; what data items are modified; what outputs
: are generated; and the follow-up tasks that will use the output.
: The traditional approach of using synchronization primitives (locks, etc) as
: the sole means of "telling" the scheduling environment is the biggest

avatar
a*f
25
去学学elrang,go,akka的并行处理机制对你会更有帮助。
avatar
p*2
26

确实

【在 a*f 的大作中提到】
: 去学学elrang,go,akka的并行处理机制对你会更有帮助。
avatar
l*3
27
不能同意更多

★ 发自iPhone App: ChineseWeb 7.8

【在 c*m 的大作中提到】
: 一些建议:
: 1. DataStore if I understand correctly is a read only object, 完全没必要
: synchronized。做成immutable就行了
: 2. CPU没有那么smart, 会知道JVM快用完memory而只用一个thread。最可能的是设计有
: 问题。
: 3. 任何有non-significant load的地方,都不要简单地用synchronized keyword,用
: concurrent collection效率更高。
: 4. thread 数量完全可以超过core的数量,只要你的程序不是完全CPU bound or IO
: bound, 哪怕是单核用multi-threading也有好处。
: 5. 如果需要Map自动清理entry, 可以考虑WeakReference。用一个thread来确保内存不

avatar
l*o
28
我的一些看法:

有问题。
听楼主描述的现象是发生了page Thrashing.
IO bound的情况下,用多线程是非常有好处的。
在单CPU情况下,只有完全CPU bound的情况下,多线程是不利的。而且,多线程还可能
会引起false sharing,锁的开销等wanting。

【在 c*m 的大作中提到】
: 一些建议:
: 1. DataStore if I understand correctly is a read only object, 完全没必要
: synchronized。做成immutable就行了
: 2. CPU没有那么smart, 会知道JVM快用完memory而只用一个thread。最可能的是设计有
: 问题。
: 3. 任何有non-significant load的地方,都不要简单地用synchronized keyword,用
: concurrent collection效率更高。
: 4. thread 数量完全可以超过core的数量,只要你的程序不是完全CPU bound or IO
: bound, 哪怕是单核用multi-threading也有好处。
: 5. 如果需要Map自动清理entry, 可以考虑WeakReference。用一个thread来确保内存不

avatar
p*2
29

大牛能不能比较一下多线程和异步编程呢?多线程有什么优势?

【在 l*****o 的大作中提到】
: 我的一些看法:
:
: 有问题。
: 听楼主描述的现象是发生了page Thrashing.
: IO bound的情况下,用多线程是非常有好处的。
: 在单CPU情况下,只有完全CPU bound的情况下,多线程是不利的。而且,多线程还可能
: 会引起false sharing,锁的开销等wanting。

avatar
l*o
30
我试着对楼主的方法进行点评一下,好像还有许多地方是可以提高的。
《《(1)将原来的逐行读取,逐行处理,改为先将每个文件的所有行读到一个新建的
DataStore 中。
这步是可以用memory mapped file进行提高的。如果单线程读取所有的文件,那么这部
分工作就变成串行化了。
《《(4)现在由于多线程异步处理,直接输出无法保证顺序。就先把这部分信息存储
到一个新建的 map 中,保存记录 ID -> data 的映射。当一个文件处理完了,才最后
按 ID 从map 有序输出到 XML 中。
为了保证顺序,其实还有其它方式可以处理的。比如,我们可以输出到不同文件中,最
后用脚本把所有东西重新拼成一个新的文件。
avatar
n*t
31
这东西用 thread干什么?又不会快。

【在 r******r 的大作中提到】
: 有点点长啊。
: 有一个 tool, 以前处理的数据比较少,所以速度,时间都不成问题。但现在需要处理
: 的数据增大,速度问题就突出了。费了好大一番力气,总算弄通了,一次处理的时间由
: 原来的 24 个小时,减小为 3 个小时。
: 第一次弄多线程,很费劲。但弄通了(只是这个小 task 弄通了,并非多线程弄通了)
: ,又觉得很有意思,小有成就感。分享一下,希望对 beginner 有帮助,也希望有经验
: 的多指教。其中有些地方,还没有完全明白,正在学习-ing。
: 程序其实也简单,就是在单机上运行的一个程序。过去单线程的,即使在多 core 的机
: 器上运行,也只能利用处理器的少部分能力。现在就是要改为多线程,多核处理。
: 数据存在 10 个文本文件中,每个大约 40M.程序从每个文件逐行读取,逐行处理,很

avatar
c*m
32
理论上,是会快的,因为
第一,楼主有多核CPU,文本in memory processing is a CPU bound process,所以多
线程处理可以加快
第二,整个程序有IO heavy和CPU heavy的两个部分,即使没有多核CPU,多线程处理也
可以减少block的时间,增加单位时间的throughput。
但是在实践中,400M的data,用现在最普通的家用PC,无论你怎么处理,都是一转眼的
事,多不多线程可能也就是几秒钟的区别。楼主这3小时的processing time实在让人很
纳闷究竟他的程序都干了啥。就算不用buffered reader, 每次读入一个char也用不了
这么久。我现在深度怀疑他没设Xmx参数,造成JVM用的default value (128 or 256M?)
。但是即使这样也不该用三个小时。

【在 n******t 的大作中提到】
: 这东西用 thread干什么?又不会快。
avatar
z*3
33
256m的是旧版本的jvm了
稍微新一点的版本都是四分之一内存

?)

【在 c*m 的大作中提到】
: 理论上,是会快的,因为
: 第一,楼主有多核CPU,文本in memory processing is a CPU bound process,所以多
: 线程处理可以加快
: 第二,整个程序有IO heavy和CPU heavy的两个部分,即使没有多核CPU,多线程处理也
: 可以减少block的时间,增加单位时间的throughput。
: 但是在实践中,400M的data,用现在最普通的家用PC,无论你怎么处理,都是一转眼的
: 事,多不多线程可能也就是几秒钟的区别。楼主这3小时的processing time实在让人很
: 纳闷究竟他的程序都干了啥。就算不用buffered reader, 每次读入一个char也用不了
: 这么久。我现在深度怀疑他没设Xmx参数,造成JVM用的default value (128 or 256M?)
: 。但是即使这样也不该用三个小时。

avatar
s*8
34
加油
avatar
z*3
35
楼主用这么长时间是因为自己写计算,输入和输出都比较缓慢造成的
统计上的一些计算算起来是挺恶心的
有几个方式可以考虑
1)用apache common math,里面statistics的lib比较好用
比自己写强多了,除非太过于冷门的分布,稍微流行一点的,这个lib里面都有
2)用r对java的接口挂上r处理
3)先用sas写好,然后转换成免费的java代码,不过这个方式要钱
对于现有的文件,最好用上db,400m对于db来说小意思
如果灰常大,上hadoop,未必需要用上多线程
倒是最有可能上多server
现在java开发,自己倒腾线程的实在是不多了
要么concurrent,要么akka,要么直接借用tomcat等server
要么用db,要么hadoop,多线程这个大问题早已经被各种软件和框架包装起来
真正去写多线程的估计都是legacy code
不过楼主这个也就是legacy code,有时候没有办法
avatar
z*3
36
"包括大量的Database IO和大量的数学运算,处理20G数据只需
要20分钟。"
这个就是你们系统跟楼主系统的差别之处
用db跟不用db差距很明显
db帮你优化了很多东西,无论是查找还是排序还是存储
甚至包括io,db连接可以建连接池,自己写的就麻烦了
所以主张尽可能多地使用现有软件,而不是自己从头写起
自己写的东西,理论上可能做得比现有软件更好
但是实际上,绝大多数人的水平差得很远
这也是搞core java最痛苦的地方
不用标准化的软件产品,一旦系统变大,瓶颈马上就呈现出来了
楼主这种系统应该是legacy code,构架师比较水
以前偷懒不用标准化软件,现在还点回去,不过这种需要parse的数据
用nosql比较好,db主要给那些需要transaction的时候用
上hadoop

【在 c*m 的大作中提到】
: 一些建议:
: 1. DataStore if I understand correctly is a read only object, 完全没必要
: synchronized。做成immutable就行了
: 2. CPU没有那么smart, 会知道JVM快用完memory而只用一个thread。最可能的是设计有
: 问题。
: 3. 任何有non-significant load的地方,都不要简单地用synchronized keyword,用
: concurrent collection效率更高。
: 4. thread 数量完全可以超过core的数量,只要你的程序不是完全CPU bound or IO
: bound, 哪怕是单核用multi-threading也有好处。
: 5. 如果需要Map自动清理entry, 可以考虑WeakReference。用一个thread来确保内存不

avatar
z*3
37
异步编程大多数时候底层就是多线程
别人帮你处理了多线程而已

【在 p*****2 的大作中提到】
:
: 大牛能不能比较一下多线程和异步编程呢?多线程有什么优势?

avatar
r*r
38
谢谢好建议。

说到 immutable,我就想到了 String. DataStore 内部实际上是一个 ArrayList, 按
序保存了数据。immutable? 我再想想
这个确实是我观察到的。当memory 快耗光时,多 core 自动变为使用一个 core,这样
程序还能勉强运行下去。
这个是确是。不过还有个疑问,比如 map, 什么时候不能使用 ConcurrentHashMap
而必须使用 synchronized map 呢?
Good to know.

我了解了一下 WeakHashMap, 我这里好像不适用。需要再看看例子
Sorry! 少 type 了一个 0, 是 4G 的数据,不是 400M. 当然,这仍然看上去是很
小的数据量,不过,这个计算确实很 expensive, 并不是这个工具本身,而是它调用其
他系统。
系统里面涉及到 inference, reasoning 等 AI 的一些处理,所以真的很 expensive
.

【在 c*m 的大作中提到】
: 一些建议:
: 1. DataStore if I understand correctly is a read only object, 完全没必要
: synchronized。做成immutable就行了
: 2. CPU没有那么smart, 会知道JVM快用完memory而只用一个thread。最可能的是设计有
: 问题。
: 3. 任何有non-significant load的地方,都不要简单地用synchronized keyword,用
: concurrent collection效率更高。
: 4. thread 数量完全可以超过core的数量,只要你的程序不是完全CPU bound or IO
: bound, 哪怕是单核用multi-threading也有好处。
: 5. 如果需要Map自动清理entry, 可以考虑WeakReference。用一个thread来确保内存不

avatar
r*r
39
我当时研究过 ArrayBlockingQueue,好像不适用。回头我再好好看看吧。
也觉得弄一个 synchronized 的 DataStore 不好,应该有现成的 class 可以利用。主
要要求就是能确保多线程下可以从一个结构里有序获得数据,而无需修改。

【在 b*******e 的大作中提到】
: Datastore 用 ArrayBlockingQueue 就可以了,设定好size.
avatar
r*r
40
我也想练练 hadoop.需要安装什么环境?自己的机器上能够配置一个,练习,了解一下吗

【在 z*******3 的大作中提到】
: 一旦会出现某一类型的任务不能在短时间内完成
: 就需要上多线程
: 楼主的这种系统应该考虑用hadoop

avatar
r*r
41
Then what are popular alternatives for such problem?
Thanks.

【在 z*y 的大作中提到】
: multi-threading is just another way to express your code
: used in right way, it may offer more readability
: but it is nothing as fancy as you think
: and for programs shooting performance and scalability
: it is not a favorable toy
: not to mention it is hard to debug

avatar
r*r
42
Need to learn more on this over time.
Thanks for the comments.

as
to

【在 k**********g 的大作中提到】
:
: There is a concept called Deterministic Parallelism which is much less
: likely to have bugs.
: Task parallelism and Data parallelism are two examples.
: The key idea is to focus on accurate declaration of data dependency to the
: scheduler. Namely, to tell the scheduling system what input data items are
: needed before a task and start; what data items are modified; what outputs
: are generated; and the follow-up tasks that will use the output.
: The traditional approach of using synchronization primitives (locks, etc) as
: the sole means of "telling" the scheduling environment is the biggest

avatar
r*r
43
再更正一下下,4G 的数据,少写了一个 0 。读取源文件当然用了 buffered reader,
这部分用时很少。主要是后期处理,涉及到 AI,真的很 expensive,没办法节约。JVM
size 是 1.5G, 够大了!

?)

【在 c*m 的大作中提到】
: 理论上,是会快的,因为
: 第一,楼主有多核CPU,文本in memory processing is a CPU bound process,所以多
: 线程处理可以加快
: 第二,整个程序有IO heavy和CPU heavy的两个部分,即使没有多核CPU,多线程处理也
: 可以减少block的时间,增加单位时间的throughput。
: 但是在实践中,400M的data,用现在最普通的家用PC,无论你怎么处理,都是一转眼的
: 事,多不多线程可能也就是几秒钟的区别。楼主这3小时的processing time实在让人很
: 纳闷究竟他的程序都干了啥。就算不用buffered reader, 每次读入一个char也用不了
: 这么久。我现在深度怀疑他没设Xmx参数,造成JVM用的default value (128 or 256M?)
: 。但是即使这样也不该用三个小时。

avatar
r*r
44
如想练练 hadoop,有什么好的 tutorial 没有?不过,这个具体任务确实用不上。这个
4G 的数据,还是很少。这个工具就像一个 utility, 虽然代码有 4000 多行。
多线程还是要好好掌握吧?因为很多地方需要用多线程,并不只是因为数据量大了。

【在 z*******3 的大作中提到】
: "包括大量的Database IO和大量的数学运算,处理20G数据只需
: 要20分钟。"
: 这个就是你们系统跟楼主系统的差别之处
: 用db跟不用db差距很明显
: db帮你优化了很多东西,无论是查找还是排序还是存储
: 甚至包括io,db连接可以建连接池,自己写的就麻烦了
: 所以主张尽可能多地使用现有软件,而不是自己从头写起
: 自己写的东西,理论上可能做得比现有软件更好
: 但是实际上,绝大多数人的水平差得很远
: 这也是搞core java最痛苦的地方

avatar
n*t
45
就是不会快。 道理自己想。

?)

【在 c*m 的大作中提到】
: 理论上,是会快的,因为
: 第一,楼主有多核CPU,文本in memory processing is a CPU bound process,所以多
: 线程处理可以加快
: 第二,整个程序有IO heavy和CPU heavy的两个部分,即使没有多核CPU,多线程处理也
: 可以减少block的时间,增加单位时间的throughput。
: 但是在实践中,400M的data,用现在最普通的家用PC,无论你怎么处理,都是一转眼的
: 事,多不多线程可能也就是几秒钟的区别。楼主这3小时的processing time实在让人很
: 纳闷究竟他的程序都干了啥。就算不用buffered reader, 每次读入一个char也用不了
: 这么久。我现在深度怀疑他没设Xmx参数,造成JVM用的default value (128 or 256M?)
: 。但是即使这样也不该用三个小时。

avatar
z*3
46
java相关的各种软件有哪怕一个东西是不能在你机器上配置和练习的么?

下吗

【在 r******r 的大作中提到】
: 我也想练练 hadoop.需要安装什么环境?自己的机器上能够配置一个,练习,了解一下吗
avatar
z*3
47
不是server吧
server才给1.5G内存就是joke了,20G比较合理

JVM

【在 r******r 的大作中提到】
: 再更正一下下,4G 的数据,少写了一个 0 。读取源文件当然用了 buffered reader,
: 这部分用时很少。主要是后期处理,涉及到 AI,真的很 expensive,没办法节约。JVM
: size 是 1.5G, 够大了!
:
: ?)

avatar
z*3
48
你用java做任何东西,脑子里首先想到的是用现成的各种工具
框架容器数据存储等,然后才是自己动手去写,除非上头有要求
比如涉及到政府的一些机密系统,需要100%读懂源代码
但是大多数时候,都不用你亲力亲为
当然多线程是一个概念
学过java的都学过这一章,作为基本功,要掌握
但是工作中,能避开就避开,一般都交给各种现成的工具
所谓不要重复造轮子
你这种用hadoop就好了,如果精度要求高,用db
db用postgresql,hadoop就有nosql,现在这两个都是文艺青年用的
公孙大神说的
server,文艺点用spring+tomcat,学术点用jboss
这个主要是event
event vs thread那个event,生命周期交给tomcat/jboss这些去管理
如果你真想用thread,从启动到销毁,那就用akka
这些是新的选择,而concurrent那个包主要是针对旧的legacy code做优化用的
因为把旧的代码全部换成akka这些,成本很高,未必值得去做
所以不同的剧本适用不同的工具,包括rmi这些
其实这些底层都是多线程,作为概念你要理解,但是自己去写
我觉得是没有必要了

【在 r******r 的大作中提到】
: 如想练练 hadoop,有什么好的 tutorial 没有?不过,这个具体任务确实用不上。这个
: 4G 的数据,还是很少。这个工具就像一个 utility, 虽然代码有 4000 多行。
: 多线程还是要好好掌握吧?因为很多地方需要用多线程,并不只是因为数据量大了。

avatar
z*3
49
还有工作流engine和web service这些,也都是多线程搞的
包括ui都有自己的多线程,比如swing的invokelater
javafx的task&service
有jvm的地方就有多线程
包括所谓的单线程,异步和event,其实底层都用到了多线程
但就是说没有必要自己去搞这些底层的多线程api
就算写出来了,后面的人看起来很痛苦
看源代码永远都是很痛苦的一件事
不仅写得好得很少,可读性差,大部分代码写得乱七八糟
而且文档通常也不存在,也不能借用其它公司的工作经验
可维护性变得很差,成本就高了
不过楼主的剧本适用java.util.concurrent
avatar
c*m
50
我们的DB是batch load, 跟楼主的应该差不多。计算还是in mem的。

【在 z*******3 的大作中提到】
: "包括大量的Database IO和大量的数学运算,处理20G数据只需
: 要20分钟。"
: 这个就是你们系统跟楼主系统的差别之处
: 用db跟不用db差距很明显
: db帮你优化了很多东西,无论是查找还是排序还是存储
: 甚至包括io,db连接可以建连接池,自己写的就麻烦了
: 所以主张尽可能多地使用现有软件,而不是自己从头写起
: 自己写的东西,理论上可能做得比现有软件更好
: 但是实际上,绝大多数人的水平差得很远
: 这也是搞core java最痛苦的地方

avatar
c*m
51
4G data也不大。不知道你有什么限制把xmx设在1.5G。如果你用64bit JVM,完全可以
设成6G,8G,足够把数据全load进去一次性完成计算。 如果必须用32bit, 至少也可以
设的尽量高一些。
我想不出什么地方不能用ConcurrentHashMap只能用synchronizedHashMap。像这种不分
青红皂白把一个instance全用一个lock object锁住的case, 都要慎重。尤其是对于non
trivial的method call。
我现在大概理解你为什么datastore要synchronized了,因为内存不够,不能一次读进
来,所以它在给别的thread提供数据的同时还要读文件。既然你的数据每行都有编号可
以独立标识,又会存到一个map里,那么我觉得这个datastore的存在除了临时存一下文
件,没有太大必要。你完全可以抛弃这个datastore, 让十个thread自己去读文件,把
同一个stream都pass给他们就可以了。这样肯定会增加throughput, 也会减少对内存的
需求。
对于Map cache, 你用一个thread去清理,是非常不reliable的。如果weakreference不
合适,你又一定要自己管理,可以让每个thread用完map entry之后自己把它清掉。
最后就是,处理4G数据,无论用多么复杂的计算,3个小时听上去都太长了,你应该
Profile一下你的程序,看看瓶颈在哪儿。

【在 r******r 的大作中提到】
: 谢谢好建议。
:
: 说到 immutable,我就想到了 String. DataStore 内部实际上是一个 ArrayList, 按
: 序保存了数据。immutable? 我再想想
: 这个确实是我观察到的。当memory 快耗光时,多 core 自动变为使用一个 core,这样
: 程序还能勉强运行下去。
: 这个是确是。不过还有个疑问,比如 map, 什么时候不能使用 ConcurrentHashMap
: 而必须使用 synchronized map 呢?
: Good to know.
:

avatar
c*m
52
最烦你这种,有话说话,没话闭嘴,因为这是中新版?

【在 n******t 的大作中提到】
: 就是不会快。 道理自己想。
:
: ?)

avatar
N*7
53
这个应该是JVM在GC了,内存全用了JVM就要做full gc,这是freeze whole world的,
而且只能一个thread做。

【在 l*****o 的大作中提到】
: 我的一些看法:
:
: 有问题。
: 听楼主描述的现象是发生了page Thrashing.
: IO bound的情况下,用多线程是非常有好处的。
: 在单CPU情况下,只有完全CPU bound的情况下,多线程是不利的。而且,多线程还可能
: 会引起false sharing,锁的开销等wanting。

avatar
z*3
54
呼呼,你楼上一凶
猴屁股都被你吓走了
我觉得他说不会快的理由大概跟你这个看到的一致
也就是在datasource的时候,楼主用了同步
所以所有线程不得不排队读取
而且貌似楼主对于输出也做了同步,而且要依次输出
所以输入和输出同时被掐住,都需要排队的前提下
那么除非中间处理时间很长,否则是不会快的
因为这样的话,单线程跟多线程其实木有太大区别
反正输入和输出都要排队,中间的多线程如果在单核机器上的话
其实也是伪的多线程,所以不会快
所以多线程最主要的是隔离线程之间的通信
通信越少多线程越有优势
这也是spring这个框架的理论基础
所有的组件都推荐是无状态的
所有变量跟线程本身绑定,变成thread local
然后这样就可以尽最大可能提高效率

non

【在 c*m 的大作中提到】
: 4G data也不大。不知道你有什么限制把xmx设在1.5G。如果你用64bit JVM,完全可以
: 设成6G,8G,足够把数据全load进去一次性完成计算。 如果必须用32bit, 至少也可以
: 设的尽量高一些。
: 我想不出什么地方不能用ConcurrentHashMap只能用synchronizedHashMap。像这种不分
: 青红皂白把一个instance全用一个lock object锁住的case, 都要慎重。尤其是对于non
: trivial的method call。
: 我现在大概理解你为什么datastore要synchronized了,因为内存不够,不能一次读进
: 来,所以它在给别的thread提供数据的同时还要读文件。既然你的数据每行都有编号可
: 以独立标识,又会存到一个map里,那么我觉得这个datastore的存在除了临时存一下文
: 件,没有太大必要。你完全可以抛弃这个datastore, 让十个thread自己去读文件,把

avatar
z*3
55
多线程最好要割离各个资源之间的联系
对于互相依赖的部分,其实很难用多线程来优化
而且会因为资源之间的协调而导致冲突
造成额外的浪费,还不如用单线程
常见的就是游戏客户端,其实大部分游戏界面都是伪多线程
其本质就是一个单线程程序
现在连web也在逐步变成单线程的
当然还是有多线程,但是并不是完全意义上的多线程
而是主线程+分支线程,类似swing那种模式
对于特别消耗时间的任务,才新起线程去做
其他的,主线程搞定
真正的多线程现在仅仅在企业系统集成的后端才会看到
前端交给单线程去搞定
avatar
c*m
56
我以为他是in general的说多线程。绝大多数DataSource是thread safe的,所以对DS
的操作完全不需要synchronized。不过,即使是最极端的情况,每次只允许一个thread
access DataSource,也还是会快。因为他的程序是个IO和CPU交互或者同时进行的过
程,在这种情况下,单线程只能做一会CPU,做一会IO。如果用多线程,即使IO和计算
本身全是单线程,至少IO和CPU可以同时进行了。更不要说IO和CPU本身也都可以用多线
程优化了。

【在 z*******3 的大作中提到】
: 呼呼,你楼上一凶
: 猴屁股都被你吓走了
: 我觉得他说不会快的理由大概跟你这个看到的一致
: 也就是在datasource的时候,楼主用了同步
: 所以所有线程不得不排队读取
: 而且貌似楼主对于输出也做了同步,而且要依次输出
: 所以输入和输出同时被掐住,都需要排队的前提下
: 那么除非中间处理时间很长,否则是不会快的
: 因为这样的话,单线程跟多线程其实木有太大区别
: 反正输入和输出都要排队,中间的多线程如果在单核机器上的话

avatar
c*e
57
当初我用c++自己from scratch手写排序的code,没有抄网上一個字,排序非常的慢。后
来发现,居然是printf()太多,让程序变慢了。把printf()删掉后,程序就非常快了。

non

【在 c*m 的大作中提到】
: 4G data也不大。不知道你有什么限制把xmx设在1.5G。如果你用64bit JVM,完全可以
: 设成6G,8G,足够把数据全load进去一次性完成计算。 如果必须用32bit, 至少也可以
: 设的尽量高一些。
: 我想不出什么地方不能用ConcurrentHashMap只能用synchronizedHashMap。像这种不分
: 青红皂白把一个instance全用一个lock object锁住的case, 都要慎重。尤其是对于non
: trivial的method call。
: 我现在大概理解你为什么datastore要synchronized了,因为内存不够,不能一次读进
: 来,所以它在给别的thread提供数据的同时还要读文件。既然你的数据每行都有编号可
: 以独立标识,又会存到一个map里,那么我觉得这个datastore的存在除了临时存一下文
: 件,没有太大必要。你完全可以抛弃这个datastore, 让十个thread自己去读文件,把

avatar
p*2
58

这个很正常呀。写log什么都会拖慢速度。

【在 c*********e 的大作中提到】
: 当初我用c++自己from scratch手写排序的code,没有抄网上一個字,排序非常的慢。后
: 来发现,居然是printf()太多,让程序变慢了。把printf()删掉后,程序就非常快了。
:
: non

avatar
c*m
59
这个对初学者来说的确很常见。其实常用的OS都支持I/O多线程。如果不想用多线程,
Java还可以用NIO的nonblocking stream。
还有一种隐藏的I/O congestion就是平时没事,一旦出错,因为很多log level都是设
成error, 出错的时候才输出,突然增加大量的I/O请求,像雪崩一样,形成正反馈,结
果一个不是很严重的错误就引发系统崩溃。这个情况如果没经验的话,调试的时候经常
想不到,到prod出现一次才意识到。

【在 c*********e 的大作中提到】
: 当初我用c++自己from scratch手写排序的code,没有抄网上一個字,排序非常的慢。后
: 来发现,居然是printf()太多,让程序变慢了。把printf()删掉后,程序就非常快了。
:
: non

avatar
p*2
60

大牛真是经验丰富呀。

【在 c*m 的大作中提到】
: 这个对初学者来说的确很常见。其实常用的OS都支持I/O多线程。如果不想用多线程,
: Java还可以用NIO的nonblocking stream。
: 还有一种隐藏的I/O congestion就是平时没事,一旦出错,因为很多log level都是设
: 成error, 出错的时候才输出,突然增加大量的I/O请求,像雪崩一样,形成正反馈,结
: 果一个不是很严重的错误就引发系统崩溃。这个情况如果没经验的话,调试的时候经常
: 想不到,到prod出现一次才意识到。

avatar
c*e
61
看见一个legacy code,jsp里面全部是scriptlet,if语句,里面弄个,这种
legacy code改成el非常麻烦。

【在 z*******3 的大作中提到】
: 还有工作流engine和web service这些,也都是多线程搞的
: 包括ui都有自己的多线程,比如swing的invokelater
: javafx的task&service
: 有jvm的地方就有多线程
: 包括所谓的单线程,异步和event,其实底层都用到了多线程
: 但就是说没有必要自己去搞这些底层的多线程api
: 就算写出来了,后面的人看起来很痛苦
: 看源代码永远都是很痛苦的一件事
: 不仅写得好得很少,可读性差,大部分代码写得乱七八糟
: 而且文档通常也不存在,也不能借用其它公司的工作经验

avatar
x*o
62

re

【在 p*****2 的大作中提到】
:
: 大牛真是经验丰富呀。

avatar
o*2
63
刚看到这个一个月前的post,看到大家讨论得热火朝天,也想插一嘴,结果发现我都没
有看明白楼主的任务。
1,这十个文件显然是有一定并发度的,但能并发到什么程度呢?并发程度是由文件内
容决定的,还是由文件名字(本身地位)决定的?
2,文件后面有多少个process centers?能否形成一个chain?
3,每个process center都哪些data,用十个文件里的哪些,还是全部?(和 1 关联)
4,process centers互相之间的dependency如何?它们用的和输出的data dependency
又如何?
没有这些信息很难决定怎么设计吧?
相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。