2

我正在尝试使用 boost 库对一段代码进行多线程处理。问题是每个线程都必须访问和修改几个全局变量。我正在使用互斥锁来锁定共享资源,但程序最终会花费更多时间而不是多线程。关于如何优化共享访问的任何建议?

非常感谢!

在下面的示例中,必须锁定 *choose_ecount* 变量,并且我不能将其从循环中取出并锁定它以仅在循环结束时进行更新,因为内部函数需要最新值。

for(int sidx = startStep; sidx <= endStep && sidx < d.sents[lang].size(); sidx ++){
    sentence s = d.sents[lang][sidx];
    int senlen = s.words.size();
    int end_symb = s.words[senlen-1].pos;

    inside(s, lbeta);
    outside(s,lbeta, lalpha);
    long double sen_prob = lbeta[senlen-1][F][NO][0][senlen-1];

    if (lambda[0] == 0){
        mtx_.lock();
        d.sents[lang][sidx].prob = sen_prob;
        mtx_.unlock();
    }

    for(int size = 1; size <= senlen; size++)
        for(int i = 0; i <= senlen - size ; i++)
        {
            int j = i + size - 1;
            for(int k = i; k < j; k++)
            {
                int hidx = i;   int head = s.words[hidx].pos;
                for(int r = k+1; r <=j; r++)
                {
                    int aidx = r;   int arg  = s.words[aidx].pos;
                        mtx_.lock();
                    for(int kids = ONE; kids <= MAX; kids++)
                    {
                        long double num = lalpha[hidx][R][kids][i][j] * get_choose_prob(s, hidx, aidx) *
                                lbeta[hidx][R][kids - 1][i][k] * lbeta[aidx][F][NO][k+1][j];
                        long double gen_right_prob = (num / sen_prob);

                        choose_ecount[lang][head][arg] += gen_right_prob; //LOCK
                        order_ecount[lang][head][arg][RIGHT] += gen_right_prob; //LOCK
                    }
                        mtx_.unlock();
                }

}

4

3 回答 3

1

从您发布的代码中,我只能看到写入choose_ecount 和order_ecount。那么为什么不使用本地每个线程缓冲区来计算总和,然后在最外层循环之后将它们相加并只同步这个操作呢?

编辑:如果您需要访问choose_ecount 的中间值,您如何确保存在正确的中间值?一个线程可能同时完成了其循环的 2 次迭代,同时在另一个线程中产生不同的结果。

听起来您需要为计算使用屏障。

于 2013-06-28T18:02:57.697 回答
0

我猜你把你的完整问题分成从startStependStep到由每个线程处理的块。

由于您已将其锁定mutex在那里,因此您有效地序列化了所有线程:您将问题分成一些块,这些块以串行但未指定的顺序处理。这是你唯一得到的就是做多线程的开销。

由于您在doubles 上进行操作,因此您不能选择使用原子操作:它们通常仅针对整数类型实现。

唯一可能的解决方案是遵循 Kratz 的建议,为每个线程创建一个副本,choose_ecountorder_ecount在线程完成后将它们减少为一个。

于 2013-06-28T18:43:50.967 回答
0

在内部循环中使用互斥锁不太可能获得可接受的性能。并发编程很困难,不仅对程序员而且对计算机也是如此。现代 CPU 的很大一部分性能来自能够将代码块视为独立于外部数据的序列。对单线程执行有效的算法通常不适合多线程执行。

你可能想看看boost::atomic,它可以提供无锁同步,但是原子操作所需的内存屏障仍然不是免费的,所以你可能仍然会遇到问题,你可能不得不重新考虑你的算法。

于 2013-06-28T17:32:31.770 回答