实践-创建多少线程合适
# 创建多少线程合适?
根据文章Java线程(中):创建多少线程才是合适的? (opens new window)
# 我总结了
为什么要使用多线程?
因为程序执行多任务时,可以执行的更快,快 取决于 延迟 ,吞吐量 。降低延迟,提高吞吐量
多线程的应用场景有哪些? io密集型:磁盘和内存打交道之类的操作 cpu密集型:复杂计算,几乎不操作磁盘,就是一个劲的计算
线程数如何创建?
cpu密集型 线程数和cpu核数相等就行(不过在工程上,线程的数量一般会设置为“CPU 核数 +1”),为什么呢?
假设只有cpu计算,io操作很少甚至没有的一个场景;
- 线程数如果少于cpu核数,如果计算量充足的情况下,每个线程都是正常工作,没有线程切换,但是存在cpu核没有利用到的情况,这是cpu利用率不足。
- 线程数如果多于CPU核数,如果计算量充足的情况下,那么多出来的线程会争抢CPU资源,造成线程切换的成本。
io密集型 最佳线程数 =CPU 核数 * [ 1 +(I/O 耗时 / CPU 耗时)] (工程上,一般是cpu核数*2+1
# 针对io密集型和cpu密集型的合适线程数实践
# 本机配置
# 实验代码
/**
* @author ggBall
* @version 1.0.0
* @ClassName IoTest.java
* @Description TODO
* @createTime 2022年07月06日 14:48:00
*/
public class PerformanceTest {
String classFilePath = PerformanceTest.class.getResource("").getPath();
CountDownLatch latch;
/**
* 按照公式 io密集型 线程数=核数*2+1 本机8核 线程数应该是17
* 结果 20次的10000次io操作 (8核*2+1)10个线程操作 平均1705.3ms
* 结果 20次的10000次io操作 (8核*2+1)11个线程操作 平均1605.35ms
* 结果 20次的10000次io操作 (8核*2+1)12个线程操作 平均1595.45ms
* 结果 20次的10000次io操作 (8核*2+1)13个线程操作 平均1625.1ms
* 结果 20次的10000次io操作 (8核*2+1)14个线程操作 平均1648.65ms
* 结果 20次的10000次io操作 (8核*2+1)15个线程操作 平均1654.95ms
* 结果 20次的10000次io操作 (8核*2+1)16个线程操作 平均1655.3ms
* 结果 20次的10000次io操作 (8核*2+1)17个线程操作 平均1645.5ms
* 结果 20次的10000次io操作 (8核*2+1)18个线程操作 平均1645.6ms
* 结果 20次的10000次io操作 (8核*2+1)19个线程操作 平均1661.35ms
* 结果 20次的10000次io操作 (8核*2+1)20个线程操作 平均1675.95ms
* @throws InterruptedException
*/
@Test
public void ioTest() throws InterruptedException {
int ioTimes = 10000;
int threadNum;
for (int i1 = 10; i1 <= 20; i1++) {
threadNum = i1;
ArrayList<Long> times = new ArrayList<>();
for (int i = 0; i < 20; i++) {
long time = singleIo(ioTimes, threadNum);
times.add(time);
}
Double avgTime = times.stream().collect(Collectors.averagingLong(item -> item));
// System.out.println(times);
System.out.println("结果 20次的"+ioTimes+"次io操作 (8核*2+1)"+threadNum+"个线程操作 平均"+avgTime+"ms");
}
}
/**
* 按照公式 cpu密集型 线程数=核数 本机8核 线程数应该是8
* 结果 20次的10000次cpu操作 (8核*2+1)15个线程操作 平均2.0ms
* 结果 20次的10000次cpu操作 (8核*2+1)14个线程操作 平均1.85ms
* 结果 20次的10000次cpu操作 (8核*2+1)13个线程操作 平均2.0ms
* 结果 20次的10000次cpu操作 (8核*2+1)12个线程操作 平均1.6ms
* 结果 20次的10000次cpu操作 (8核*2+1)11个线程操作 平均1.5ms
* 结果 20次的10000次cpu操作 (8核*2+1)10个线程操作 平均1.6ms
* 结果 20次的10000次cpu操作 (8核*2+1)9个线程操作 平均1.55ms
* 结果 20次的10000次cpu操作 (8核*2+1)8个线程操作 平均1.35ms
* 结果 20次的10000次cpu操作 (8核*2+1)7个线程操作 平均1.4ms
* 结果 20次的10000次cpu操作 (8核*2+1)6个线程操作 平均1.6ms
* 结果 20次的10000次cpu操作 (8核*2+1)5个线程操作 平均1.45ms
* 结果 20次的10000次cpu操作 (8核*2+1)4个线程操作 平均1.4ms
* 结果 20次的10000次cpu操作 (8核*2+1)3个线程操作 平均1.0ms
* 结果 20次的10000次cpu操作 (8核*2+1)2个线程操作 平均1.7ms
* @throws InterruptedException
*/
@Test
public void cpuTest() throws InterruptedException {
int cpuTimes = 10000;
int threadNum;
for (int i1 = 16; i1 > 1; i1--) {
threadNum = i1;
ArrayList<Long> times = new ArrayList<>();
for (int i = 0; i < 20; i++) {
long time = singleCPU(cpuTimes, threadNum);
times.add(time);
}
Double avgTime = times.stream().collect(Collectors.averagingLong(item -> item));
// System.out.println(times);
System.out.println("结果 20次的"+cpuTimes+"次cpu操作 (8核*2+1)"+threadNum+"个线程操作 平均"+avgTime+"ms");
}
}
/**
* 执行单次多线程cpu任务
* @param cpuTimes
* @param threadNum
* @return
* @throws InterruptedException
*/
private long singleCPU(int cpuTimes, int threadNum) throws InterruptedException {
latch = new CountDownLatch(cpuTimes);
long start = System.currentTimeMillis();
// 170次io操作 (8核*2+1)17个线程操作
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
for (int i = 0; i < cpuTimes; i++) {
CPUTasker tasker = new CPUTasker();
executorService.submit(tasker);
}
latch.await();
long end = System.currentTimeMillis();
// System.out.println(end-start+"ms");
return end-start;
}
/**
* 执行单次多线程io任务
* @param ioTimes
* @param threadNum
* @return
* @throws InterruptedException
*/
public long singleIo(int ioTimes,int threadNum) throws InterruptedException {
latch = new CountDownLatch(ioTimes);
long start = System.currentTimeMillis();
// 170次io操作 (8核*2+1)17个线程操作
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
for (int i = 0; i < ioTimes; i++) {
IoTasker tasker = new IoTasker();
executorService.submit(tasker);
}
latch.await();
long end = System.currentTimeMillis();
// System.out.println(end-start+"ms");
return end-start;
}
/**
* io任务
*/
class IoTasker implements Runnable{
@Override
public void run() {
String fileName = "text.txt";
FIleUtils fIleUtils = new FIleUtils();
fIleUtils.writeFile(classFilePath+ "/" + fileName,"sda实打实大sss11212");
try {
fIleUtils.fileRead(classFilePath+ "/" + fileName);
// System.out.println(Thread.currentThread().getName()+"io完成");
latch.countDown();
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
}
/**
* cpu任务
*/
class CPUTasker implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1024; i++) {
for (int j = 0; j < 1024; j++) {
for (int k = 0; k < 1024; k++) {
}
}
}
latch.countDown();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# 实践总结
从实验代码看,io密集型设置的线程数 确实符合 线程数=核数*2+1
公式,测试结果显示17个线程耗时最少;但是cpu密集型 从线程数3~12个 耗时都在1.5ms左右,与公式线程数=核数
相差很大,
所以设置线程的公式只是参考标准,生产环境还得实际测试。
# 问题
I/O 耗时 和 CPU 耗时 不知道使用什么工具测试?
上次更新: 2022/08/23, 12:44:32