仅在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线程?
我认为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)。对于每个线程来说,滚动自己的线程会带来很多麻烦)
现在你的选择已经结束,你可以做更新,但即使在一个线程中,你仍然可以得到死锁与其他任务,你的代码应该预期和处理它。