【发布时间】:2017-04-26 16:52:47
【问题描述】:
我正在使用 Parallel.ForEach 在 Oracle DB 上执行一些工作,我从日志中看到它没有将负载分成 N 个块,其中 N = MaxDegreeOfParallelism。这是意料之中的,因为每个块可能需要更长或更短的时间来处理,但是块确实将工作负载分成太小。如果池处于启用状态 (ORA-12518),ODP.NET 会由于某种原因使打开连接的数据库过载,所以我禁用了它。这消除了错误,但我想减少打开和关闭连接所花费的时间。
有没有办法影响Parallel.ForEach 将工作负载分成更大的块?
作为参考,这是代码当前的样子:
//conn is the primary connection stored in the object
logger.Report("Started");
var allObjects = GetObjects(); //uses the primary connection
logger.Report(string.Format("Retrieved {0} objects", allObjects.Count));
var i = allObjects.Count;
var taskID = 0;
Parallel.ForEach(
allObjects,
new ParallelOptions { MaxDegreeOfParallelism = 16, },
() => {
var c = (DbConnection)((ICloneable)conn).Clone();
c.Open();
var t = Interlocked.Increment(ref taskID);
logger.Report(string.Format("Task #{0} started", t));
return (conn: c, task: t);
},
(o, loopState, c) => {
try {
var objectName = o.Name;
var objectType = o.Type;
logger.Report(string.Format("Retrieving {0} {1}", objectType, objectName));
var dbObject = GetObject(c.conn, o.Name, o.Type);
logger.Report(string.Format("Processing {0} {1}", objectType, objectName));
var result = ProcessObject(dbObject);
logger.Report(string.Format("Recompiling {0} {1}", objectType, objectName));
ProcessResult(c.conn, result);
logger.Report(string.Format("{0} objects remaining", Interlocked.Decrement(ref i)));
return c;
} catch (Exception ex) {
logger.Report("ERROR: " + ex);
throw;
}
},
c => {
logger.Report(string.Format("Task #{0} finished", c.task));
c.conn.Close();
c.conn.Dispose();
});
logger.Report("Recompiling invalids...");
RecompileInvalids(); //uses the primary connection
logger.Report("Done");
【问题讨论】:
-
@SergeySlepov 谢谢,看来我必须实现自己的分区器
-
@Alexey 你不需要自己实现。只需specify the chunk size
标签: c# oracle parallel-processing task-parallel-library