我有两段代码如下,一个使用Thread,一个使用Parallel.Foreach
发
foreach (var i in new int [] {0, 1, 2, 3, 4, ..., 24 })
new Thread(GET_DATA).Start(i);
并行
Parallel.Foreach(new int [] {0, 1, 2, 3, 4, ..., 24 }, GET_DATA);
使用方法GET_DATA
void GET_DATA(object state) {
var x = (int)state;
using (var conn = new OracleConnection(cs[x])) {
conn.Open();
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = "select * from dual";
var dt = new DataTable();
dt.Load(cmd.ExecuteReader());
}
}
}
和cs是25 Oracle Database的连接字符串数组
我使用Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
和16GB RAM
,来自nuget的Oracle.ManagedDataAccess库中的OracleConnection。
第一次没有创建连接池时
Thread approach
:所有线程在运行后3到5秒停止Parallel approach
:运行后12至15秒并行停止下次,两种方法的结果相似,因为创建了连接池。
我猜单核上的并行运行应该比线程慢近4倍,有人可以解释一下吗?
谢谢
答案 0 :(得分:3)
在你的第一个例子中,你产生了24个线程,它们将通过等待I / O操作(建立与数据库的套接字连接)来完成。
在第二个示例中,您使用未知数量的线程(取决于核心数和并行化设置的程度)来处理24个项目的列表。每个线程将以串行方式处理项目的子集。
由于操作在您的进程中不受CPU限制,而是依赖于外部进程(数据库的I / O,数据库上的操作等),Parallel.Foreach
将浪费大量时间在开始下一个任务之前等待一项任务完成。
示例强>
X是操作的完成,时间是垂直的,线程是水平的。
使用24个线程时:
1 2 3 ... 24 Time
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
X X X X V
使用4个线程处理24个项目时:
1 2 3 4 Time
| | | | |
| | | | |
| | | | |
X X X X |
| | | | |
| | | | |
| | | | |
X X X X |
| | | | |
| | | | |
| | | | |
X X X X |
. . . . |
. . . . |
. . . . V
答案 1 :(得分:2)
Parallel.Foreach(new int [] {0, 1, 2, 3, 4, ..., 24 }, GET_DATA);
请同时将其添加到Parallel.Foreach
,以使两个示例使用相同数量的线程。
new ParallelOptions { MaxDegreeOfParallelism = 24 }
对于普通foreach
,这将等待所有线程在退出循环之前完成
foreach (var i in new int [] {0, 1, 2, 3, 4, ..., 24 })
new Thread(GET_DATA).Start(i);
如果你等待所有线程完成,我相信你会得到相同的结果。