2

My app in c# is working this way. I start as many threads as it is value in config file (dynamic creation of threads). What every thread is doing is: it goes to DB, calls stored procedure (if I have 60 threads, there are deadlocks). After that, every thread is calling web service, and going back to update rows. Here is how it is looking like

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
        }
    }
}

I would like to do this in a DB less expensive way. I would like only once to go to DB, and after that to create sublists from object messages. After that I will create as many threads as sublists, and those sublists I will pass to send() method. Each thread will call send() method. But when I finish everything, how can I get out of threads and only once call stored procedure to update (updateMessage() method)? How can I do this in a way to only use threads only to call web service, and at same time to call Db out of threads?

4

4 回答 4

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 服务会阻塞。

于 2013-01-10T15:57:03.747 回答
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);
}

这样,无论有多少线程尝试同时调用数据库,一次只能运行一个调用。

于 2013-01-10T15:45:04.950 回答
0

先做你的选择,在一个线程上

然后使用线程来收集消息(我会使用Parallel.ForEach,滚动你自己的线程需要很多麻烦)

现在,您的选择无法进行更新,但即使在单个线程中,您仍然可以与其他任务发生死锁,您的代码应该期待并处理它。

于 2013-01-10T16:00:32.840 回答
0

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

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

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

于 2013-01-10T15:52:03.330 回答