首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用任务和阻塞集合时出现Oracle连接问题

使用任务和阻塞集合时出现Oracle连接问题
EN

Stack Overflow用户
提问于 2014-12-30 18:23:22
回答 2查看 573关注 0票数 0

我有一些任务(nWorkers = 3):

代码语言:javascript
复制
var taskFactory = new TaskFactory(cancellationTokenSource.Token,
    TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning,
    TaskScheduler.Default);

for (int i = 0; i < nWorkers; i++)
{
    var task = taskFactory.StartNew(() => this.WorkerMethod(parserItems,
        cancellationTokenSource));
    tasks[i] = task;
}    

以及由任务调用的下列方法:

代码语言:javascript
复制
protected override void WorkerMethod(BlockingCollection<ParserItem> parserItems,
    CancellationTokenSource cancellationTokenSource)
{
//...log-1...
using (var connection = new OracleConnection(connectionString))
{
    OracleTransaction transaction = null;
    try
    {
        cancellationTokenSource.Token.ThrowIfCancellationRequested();
        connection.Open();
        //...log-2...
        transaction = connection.BeginTransaction();
        //...log-3...
        using (var cmd = connection.CreateCommand())
        {                   
            foreach (var parserItem in parserItems.GetConsumingEnumerable(
                cancellationTokenSource.Token))
            {
                cancellationTokenSource.Token.ThrowIfCancellationRequested();
                try
                {
                    foreach (var statement in this.ProcessRecord(parserItem))
                    {                               
                        cmd.CommandText = statement;
                        try
                        {                                   
                            cmd.ExecuteNonQuery();                                  
                        }
                        catch (OracleException ex)
                        {
                            //...log-4...
                            if (!this.acceptedErrorCodes.Contains(ex.Number))
                            {
                                throw;
                            }
                        }
                    }
                }
                catch (FormatException ex)
                {
                    log.Warn(ex.Message);
                }
            }
            if (!cancellationTokenSource.Token.IsCancellationRequested)
            {                       
                transaction.Commit();                       
            }
            else
            {                       
                throw new Exception("DBComponent has been canceled");
            }
        }
    }
    catch (Exception ex)
    {
        //...log-5...
        cancellationTokenSource.Cancel();
        if (transaction != null)
        {
            try
            {
                transaction.Rollback();
                //...log-6...
            }
            catch (Exception rollbackException)
            {
                //...log-7...
            }
        }
        throw;
    }
    finally
    {
        if (transaction != null)
        {
            transaction.Dispose();
        }
        connection.Close();
        //...log-8...
    }
}
//...log-9...   
}

有一个ParserItem对象的生产者,他们是消费者。通常情况下,它可以正常工作,有时会有Oracle连接超时,但在这些情况下,我可以看到异常消息,并且一切都按照设计的方式工作。

但有时这个过程会被卡住。当它被卡住时,我可以在日志文件中看到log-1消息,然后(大约15秒后)我会看到log-8消息,但让我发疯的是,为什么我看不到异常消息log-5和log-9消息。因为从来没有调用过cancellationTokenSource.Cancel()方法,所以有界集合的项目生产者会被阻塞,直到两个小时后超时。

它是为NETFramework4编译的,我使用Oracle.ManagedDataAccess库来连接。

任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-30 20:36:33

使用作用域时,永远不应释放事务或连接。其次,您应该很少依赖基于异常的编程风格。下面重写了您的代码:

代码语言:javascript
复制
using (var connection = new OracleConnection(connectionString))
{
    using (var transaction = connection.BeginTransaction())
    {
        connection.Open();
        //...log-2...
        using (var cmd = connection.CreateCommand())
        {
            foreach (var parserItem in parserItems.GetConsumingEnumerable(cancellationTokenSource.Token))
            {
                if (!cancellationTokenSource.IsCancellationRequested)
                {
                    try
                    {
                        foreach (var statement in ProcessRecord(parserItem))
                        {
                            cmd.CommandText = statement;
                            try
                            {
                                cmd.ExecuteNonQuery();
                            }
                            catch (OracleException ex)
                            {
                                //...log-4...
                                if (!acceptedErrorCodes.Contains(ex.ErrorCode))
                                {
                                    log.Warn(ex.Message);
                                }
                            }
                        }
                    }
                    catch (FormatException ex)
                    {
                        log.Warn(ex.Message);
                    }
                }
            }
            if (!cancellationTokenSource.IsCancellationRequested)
            {
                transaction.Commit();
            }
            else
            {
                transaction.Rollback();
                throw new Exception("DBComponent has been canceled");
            }
        }
    }
}
//...log-9... 

如果这有帮助的话请告诉我。

票数 1
EN

Stack Overflow用户

发布于 2022-09-20 10:50:53

我可以确认你所说的一切。(程序卡住,CPU使用率低,甲骨文连接超时等)

解决方法之一是使用线程而不是任务。

更新:经过仔细调查后,我发现当您使用大量任务时,由Oracle驱动程序排队的ThreadPool工作线程的启动变得缓慢,最终导致(假的)连接超时。

以下是几个解决方案:

解决方案1:增加线程池的最小线程数,例如:

代码语言:javascript
复制
ThreadPool.SetMinThreads(50, 50);  // YMMV

解决方案2:将您的连接配置为使用池并适当地设置其最小大小。

代码语言:javascript
复制
var ocsb = new OracleConnectionStringBuilder();
ocsb.DataSource = ocsb.DataSource;
ocsb.UserID = "myuser";
ocsb.Password = "secret";
ocsb.Pooling = true;
ocsb.MinPoolSize = 20; // YMMV

重要事项:在调用任何创建大量任务的例程之前,请使用“热身”池打开单个连接:

代码语言:javascript
复制
using(var oc = new OracleConnection(ocsb.ToString()))
{
    oc.Open();
    oc.Close();
}

注意: Oracle通过连接字符串(删除密码)对连接池进行索引,因此,如果要打开其他连接,则必须始终使用完全相同的连接字符串。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27710525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档