我在c#中的应用就是这样做的。我启动尽可能多的线程,因为它是配置文件中的值(动态创建线程)。每个线程正在做的是:它进入DB,调用存储过程(如果我有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 ?
答案 0 :(得分:2)
我认为Parallel.ForEach()
对您的情况很有用。
您要做的是从数据库中获取列表,然后使用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
个线程,但在您的情况下,您很可能会很快达到该数字,因为调用了Web服务块。
答案 1 :(得分:0)
我不确定我是否完全理解您的问题,但如果您想将数据库调用限制为一次,则可以使用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);
}
这样,有多少线程尝试同时调用数据库并不重要,一次只能运行一个调用。
答案 2 :(得分:0)
您应该查看消费者/生产者模式,例如参见http://en.wikipedia.org/wiki/Producer-consumer_problem
您的初始化将访问数据库并启动生成器(每个都是一个单独的线程)。这些将调用Web服务并将状态记录在共享的内存中数据结构(队列)中。
单个使用者(线程)将在共享队列中查找元素,并将它们保存在数据库中并从队列中删除。
答案 3 :(得分:0)
首先在一个帖子上选择
然后使用线程来完成消息的收集(我会使用Parallel.ForEach,滚动你自己的线程会花费很多麻烦)
现在你的选择超出了你可以进行更新的方式,但即使在一个线程中,你仍然可以通过其他任务获得死锁,你的代码应该期待并处理它。