C# 交换参考变量值的最快且仍然安全的方法

C# 交换参考变量值的最快且仍然安全的方法,c#,multithreading,thread-safety,locking,C#,Multithreading,Thread Safety,Locking,基本上,我需要的是能够不断地将项目添加到列表(或另一个集合),在一个线程中大约每秒3000次。每2秒获取并删除列表中的所有项目一次 我不喜欢经典的方法,比如在每次需要访问集合时使用并发集合或锁定某些东西,因为这样做会比我需要的慢 我试图做的是有两个集合,每个线程一个,并找到一种方法使线程安全地从一个集合切换到另一个集合 简化的非线程安全示例: var listA = new List<int>(); var listB = new List<int>(); // met

基本上,我需要的是能够不断地将项目添加到列表(或另一个集合),在一个线程中大约每秒3000次。每2秒获取并删除列表中的所有项目一次

我不喜欢经典的方法,比如在每次需要访问集合时使用并发集合或锁定某些东西,因为这样做会比我需要的慢

我试图做的是有两个集合,每个线程一个,并找到一种方法使线程安全地从一个集合切换到另一个集合

简化的非线程安全示例:

var listA = new List<int>();
var listB = new List<int>();

// method is called externally 3000 times per second
void ProducerThread(int a)
{      
    listA.Add(a)      
}
void ConsumerThread()
{
  while(true)
  {
    Thread.Sleep(2000);
    listB = Interlocked.Exchange(ref listA,listB);
    //... processing listB data
    // at this point when i'm done reading data
    // producer stil may add an item because ListA.Add is not atomic
    // correct me if i'm wrong
    listB.Clear();
  }
}
var listA=new List();
var listB=新列表();
//方法每秒外部调用3000次
无效生成读取(int a)
{      
listA.Add(a)
}
void ConsumerThread()
{
while(true)
{
《睡眠》(2000年);
listB=联锁交换(参考listA,listB);
//…正在处理listB数据
//在这一点上,当我完成了数据读取
//producer stil可能会添加项目,因为ListA.add不是原子的
//如果我错了,请纠正我
listB.Clear();
}
}

是否有任何方法可以使上述代码在尽可能少地阻塞生产者线程的情况下按预期(线程安全)工作?或者另一种解决方案?

如果表有固定的最大大小,为什么要使用列表?您还可以预先设置列表大小

List<int> listA = new List<int>(6000);

您只需确保先运行ConsumerThread,这样它就会排队等待。

如果表有固定的最大大小,为什么要使用列表?您还可以预先设置列表大小

List<int> listA = new List<int>(6000);

您只需确保首先运行ConsumerRead,这样它就会排队等待。

我会首先使用System.Collections.Concurrent中的
BlockingCollection
或另一个
IProducerConsomerCollection
。这正是您所拥有的,一个从多个线程访问的生产者/消费者队列。这些集合还针对性能进行了大量优化。他们不使用天真的“在任何人进行任何操作时锁定整个结构”。它们足够聪明,可以使用无锁同步技术尽可能避免锁定,并且当它们确实需要使用关键部分时,它们可以最小化需要锁定的部分,这样即使有一定量的锁定,结构也可以经常并发访问

在我从那里转移到其他地方之前,我会使用其中一个集合,并确保它太慢。如果在使用该方法作为解决方案之后,您已经证明您花费了不可接受的时间来添加/删除集合中的项,那么您可以考虑研究其他解决方案。
如果,正如我所怀疑的那样,它们的执行速度足够快,我相信您会发现,这会使编写代码更容易、更清晰。

我会首先在System.Collections.Concurrent中使用
BlockingCollection
或另一个
IProducerConsomerCollection
。这正是您所拥有的,一个从多个线程访问的生产者/消费者队列。这些集合还针对性能进行了大量优化。他们不使用天真的“在任何人进行任何操作时锁定整个结构”。它们足够聪明,可以使用无锁同步技术尽可能避免锁定,并且当它们确实需要使用关键部分时,它们可以最小化需要锁定的部分,这样即使有一定量的锁定,结构也可以经常并发访问

在我从那里转移到其他地方之前,我会使用其中一个集合,并确保它太慢。如果在使用该方法作为解决方案之后,您已经证明您花费了不可接受的时间来添加/删除集合中的项,那么您可以考虑研究其他解决方案。
如果,正如我所怀疑的那样,它们的执行速度足够快,我相信您会发现编写代码更容易、更清晰。

我假设您只想处理新添加到
listA
,并且在处理这些添加的过程中,会进行更多的添加

var listA = new List<int>();
var dictA = new Dictionary<int,int>();

int rangeStart = 0;
int rangeEnd = 0;
bool protectRange = false;

// method is called externally 3000 times per second
void ProducerThread(int a)
{      
 listA.Add(a);
 dictA.Add(rangeEnd++,a);   
}
void ConsumerThread()
{
 while(true)
 {
  Thread.Sleep(2000);
  int rangeInstance = rangeEnd;
  var listB = new List<int>();
  for( int start = rangeStart; start < rangeInstance; start++ ){
   listB.add(dictA[start]);
   rangeStart++;
  }
  //... processing listB data
  }
}
var listA=new List();
var dictA=新字典();
int rangeStart=0;
int rangeEnd=0;
bool protectRange=false;
//方法每秒外部调用3000次
无效生成读取(int a)
{      
列表a.添加(a);
dictA.Add(rangeEnd++,a);
}
void ConsumerThread()
{
while(true)
{
《睡眠》(2000年);
int rangeInstance=rangeEnd;
var listB=新列表();
对于(int start=rangeStart;start
我假设您只想处理
列表a中的新添加项,并且在处理这些添加项的同时会进行更多的添加

var listA = new List<int>();
var dictA = new Dictionary<int,int>();

int rangeStart = 0;
int rangeEnd = 0;
bool protectRange = false;

// method is called externally 3000 times per second
void ProducerThread(int a)
{      
 listA.Add(a);
 dictA.Add(rangeEnd++,a);   
}
void ConsumerThread()
{
 while(true)
 {
  Thread.Sleep(2000);
  int rangeInstance = rangeEnd;
  var listB = new List<int>();
  for( int start = rangeStart; start < rangeInstance; start++ ){
   listB.add(dictA[start]);
   rangeStart++;
  }
  //... processing listB data
  }
}
var listA=new List();
var dictA=新字典();
int rangeStart=0;
int rangeEnd=0;
bool protectRange=false;
//方法每秒外部调用3000次
无效生成读取(int a)
{      
列表a.添加(a);
dictA.Add(rangeEnd++,a);
}
void ConsumerThread()
{
while(true)
{
《睡眠》(2000年);
int rangeInstance=rangeEnd;
var listB=新列表();
对于(int start=rangeStart;start
我认为您的代码可以工作。当你说“线程安全”时,你在寻找什么保证?你是说ListA.Add是一个原子操作?我担心制作人可能已经引用了我正在处理的列表,所以如果它在我清除列表之前出现,我可能会错过附加值。不,添加不是原子的,我现在明白你的意思了。你可以务实一点,在交换变量后做一个短暂的睡眠;ListA=新