【问题标题】:Parallel: how to synchronize properly并行:如何正确同步
【发布时间】:2010-10-17 11:12:34
【问题描述】:

我有以下相当简单的场景: 一些数据需要写入可以分区的数据库(相当大的集合)。但是我有两个问题:

  1. 简单的一个:希望有一个打印进度条的选项,以便不时知道到目前为止插入了多少条记录(线程之间共享计数器)。

  2. 更难的一个:每条记录都需要附有时间戳。时间戳具有开始时间和间隔。不幸的是,时间戳不是记录的一部分,但在顺序编程中,可以通过将当前时间戳增加特定间隔来简单地计算。

到目前为止,问题是:如何正确实现上述约束?是否有可能以某种方式将循环体与促进迭代时正在执行的代码分开(++inewTimeStamp = oldTimeStamp.AddSeconds(...),这样这种代码将始终在单个线程上执行,这与循环体相反并行化?如果可能,代码 sn-p 将非常有帮助,尽管我很乐意获得任何指针/名称/关键字。谢谢。

【问题讨论】:

  • 数据库和网络听起来像是你的瓶颈......你有基准测试吗?
  • 你说的很对。基准已尽快计划。

标签: c# multithreading parallel-processing task-parallel-library


【解决方案1】:

对于第 1 部分,您可以使用互斥体 (lock statement),甚至可以只使用 Interlocked methods 之一。

int counter = 0;
object counterLock = new object();
void IncreaseCounter()
{
    lock (counterLock)
        counter++;
}

int GetCounter()
{
    lock (counterLock)
        return counter;
}

int counter = 0;
void IncreaseCounter()
{
    Interlocked.Increment(ref counter);
}

int GetCounter()
{
    return Interlocked.Read(ref counter);
}

对于从 GUI 使用,您可以将计数器更改传播到适当的 DependencyProperty(如果您使用的是 WPF)。

对于第二部分,为什么不能单独计算每条记录的时间戳,这样你就不需要在线程之间共享任何东西了?可能我没有正确理解您的问题,能否请您更详细地描述问题#2?

【讨论】:

  • 谢谢,对于prob N1 Interlocked.Increment 正是我所需要的。第二个问题是我可以(通常)创建带有时间戳的记录数组,但它很大并且(如果可能的话)我想检查时间戳生成。生成规则非常简单:只需为每个后续记录提前特定间隔的时间戳即可。
  • @BreakPhreak:对于第二个问题,我还是不明白;也许您可以在单线程案例中发布您想要的代码?
  • record.setTimestamp(timestamp = timestamp.AddSeconds(1));但实际上谢谢 - 我刚刚想出了第二部分的公式解决方案。
  • @BreakPhreak:也许你可以使用DateTime.Now()
【解决方案2】:

您不需要在单个线程中执行此操作,您只需确保一次只有一个线程执行此操作:

public class Synchoniser {

  private int _progress;
  private int _total;
  private int _counter;
  pricate object _sync;

  public Synchroniser(int total, int counterSeed) {
    _progress = 0;
    _total = total;
    _counter = counterSeed;
    _sync = new Object();
  }

  public void AdvanceProgress() {
    lock (_sync) {
      _progress++;
    }
  }

  public int GetProgress() {
    lock (_sync) {
      return 100 * _progress / _total;
    }
  }

  public int GetNextCounter() {
    lock (_sync) {
      _counter++;
      return _counter;
    }
  }

}

创建该类的单个实例,并将其提供给每个线程。现在他们可以各自推进进度并获得下一个计数器值。

【讨论】:

  • 一切都很好,但问题 N2 仍然存在:我可以在您的同步器中添加一个时间戳字段,并在每次我推进进度时获取它。这是您的意思还是有更优化的方法来解决问题?
猜你喜欢
  • 1970-01-01
  • 2011-11-06
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 2016-10-31
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多