如何使Parallel.ForEach将工作分成更大的块?

时间:2017-04-26 08:08:01

标签: c# oracle parallel-processing task-parallel-library

我正在使用Parallel.ForEach在Oracle DB上执行一些工作,我从日志中看到它没有将负载分成N个块,其中N = MaxDegreeOfParallelism。这是预期的,因为每个块可能需要更长或更短的时间来处理,但是块确实将工作负载分成太小。 ODP.NET由于某种原因,如果打开了池(ORA-12518),则会使用开放连接使DB过载,因此我禁用了它。这消除了错误,但我想减少打开和关闭连接所花费的时间。

有没有办法影响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");

1 个答案:

答案 0 :(得分:0)

结果是将Max Pool Size=24;Connection Timeout=60;添加到连接字符串比尝试重新分区列表更好。