仅在web服务调用中使用线程,而不是在数据库调用中使用线程

本文关键字:线程 调用 数据库 服务 仅在 web | 更新日期: 2023-09-27 17:51:11

我的c#应用程序就是这样工作的。我启动尽可能多的线程,因为它是在配置文件中的值(动态创建线程)。每个线程所做的是:它去数据库,调用存储过程(如果我有60个线程,有死锁)。之后,每个线程调用web服务,并返回更新行。下面是它的样子

List<Message> messages =getMessages(ThreadNO);//goes to DB
if (messages != null)
{
    foreach (Message bm in messages)
    {
        if (bm.Status)
        {
            try
            {
                bm.send();//calls Web service
            }
            catch (Exception ex)
            {
                LOG.Logger.Error(ex.ToString());
            }
            updateStatus(bm);//goes back to DB
        }
        else
        {
            if (bm.subscribe())
                updateSubscription(bm);//calls WS
            else
                updateUnsuccessfulSubscription(bm);//calls WS
        }
    }
}

我想以一种DB更便宜的方式来做这件事。我想只有一次去DB,然后从对象消息创建子列表。之后,我将创建尽可能多的线程作为子列表,这些子列表将传递给send()方法。每个线程将调用send()方法。但是,当我完成了一切,我怎么能摆脱线程,只有一次调用存储过程更新(updateMessage()方法)?我如何才能做到这一点,只有使用线程只调用web服务,并在同一时间调用Db线程?

仅在web服务调用中使用线程,而不是在数据库调用中使用线程

我认为Parallel.ForEach()对你的情况会很有用。

您要做的是从DB中获取列表,然后使用Parallel.ForEach()并行处理这些项目,当它完成时,最后更新数据库。

类似:

var messages = GetAllMessages(); //goes to DB
Parallel.ForEach(
    messages,
    new ParallelOptions { MaxDegreeOfParallelism = threadCount },
    message => { /* your code that calls the web service */ });
UpdateAll(messages); // goes back to the DB

Parallel.ForEach()不能保证使用threadCount线程,但在您的情况下,您可能很快就会达到这个数字,因为调用webservice阻塞。

我不确定我完全理解你的问题,但如果你想限制数据库调用一次一个,你可以只使用lock:

// put this field in a class somewhere
static object gate = new object();
// then wrap all your database calls in locks:
lock( gate )
{
  updateStatus(bm);
}

这样,无论有多少线程试图并发地调用数据库,一次只能运行一个调用。

您应该查看消费者/生产者模式,例如http://en.wikipedia.org/wiki/Producer-consumer_problem

初始化将访问DB并启动生产者(每个生产者都是单独的线程)。它们将调用web服务并在共享的内存数据结构(队列)中记录状态。

单个消费者(线程)将在共享队列中查找元素,并将它们保存在DB中,然后从队列中删除。

在单个线程上先执行select

然后使用线程来遍历消息集合(我会使用Parallel)。对于每个线程来说,滚动自己的线程会带来很多麻烦)

现在你的选择已经结束,你可以做更新,但即使在一个线程中,你仍然可以得到死锁与其他任务,你的代码应该预期和处理它。