C# 从多个线程记录.NET 4

C# 从多个线程记录.NET 4,c#,.net,multithreading,concurrency,C#,.net,Multithreading,Concurrency,我有JournalService类,它收集事件的记录。这个类收集列表中的记录。事件来自多个线程。记录列表的长度有限制。我正在使用.NET4.0。 为了保证线程安全,我锁定了对“记录”列表的读写访问。 我在这方面没有经验,我也不确定我是否做得很好。 也许我必须使用 我的问题是:我是否需要修复我的代码,使用什么并发类以及如何修复 目前的代码是: public class JournalService : IJournalService { private readonly List<J

我有JournalService类,它收集事件的记录。这个类收集列表中的记录。事件来自多个线程。记录列表的长度有限制。我正在使用.NET4.0。 为了保证线程安全,我锁定了对“记录”列表的读写访问。 我在这方面没有经验,我也不确定我是否做得很好。 也许我必须使用

我的问题是:我是否需要修复我的代码,使用什么并发类以及如何修复

目前的代码是:

public class JournalService : IJournalService
{
    private readonly List<JournalRecord> records = new List<JournalRecord>();
    private readonly ISettings settings;

    public JournalService(IEventAggregator eventAggregator, ISettings settings)
    {
        if (eventAggregator == null) throw new ArgumentNullException("eventAggregator");
        if (settings == null) throw new ArgumentNullException("settings");

        this.settings = settings;
        eventAggregator.JournalRecordPosted += EventAggregator_JournalRecordPosted;
    }

    public IEnumerable<JournalRecord> GetRecords()
    {
        JournalRecord[] tempRecords;
        lock (records)
        {
            tempRecords = records.ToArray();
        }
        return tempRecords;
    }

    private void EventAggregator_JournalRecordPosted(object sender, JournalRecordEventArgs e)
    {
        lock (records)
        {
            int surplus = records.Count - settings.TradeJournalLength;
            if (surplus == 0)
                records.RemoveAt(0);
            else if (surplus > 0)
                records.RemoveRange(0, surplus);
            records.Add(e.Record);
        }
    }
}
公共类JournalService:IJournalService
{
私有只读列表记录=新列表();
私人只读设置;
public JournalsService(IEventAggregator事件聚合器、ISettings设置)
{
如果(eventAggregator==null)抛出新的ArgumentNullException(“eventAggregator”);
如果(设置==null)抛出新的ArgumentNullException(“设置”);
this.settings=设置;
eventAggregator.JournalRecordPosted+=eventAggregator\u JournalRecordPosted;
}
公共IEnumerable GetRecords()
{
日志记录[]临时记录;
锁(记录)
{
tempRecords=records.ToArray();
}
归还记录;
}
私有void EventAggregator_JournalRecordPosted(对象发送方,JournalRecordEventArgs e)
{
锁(记录)
{
int剩余=records.Count-settings.TradeJournalLength;
如果(盈余==0)
记录。删除(0);
否则,如果(盈余>0)
记录删除范围(0,剩余);
记录。添加(如记录);
}
}
}
编辑:将剩余计算放入锁中。 编辑:添加了剩余==0的检查。

您可以使用 无锁并发队列

private int _length = 0;
private void EventAggregator_JournalRecordPosted(object sender, JournalRecordEventArgs e)
{
    records.Enqueue(e.Record);


    if(Interlocked.Increment(ref _length)>=settings.TradeJournalLength)
    while(!records.Dequeue())
    {

    }
Interlocked.Decrement(ref _length)
}
使用ConcurrentQueue:

private void EventAggregator_JournalRecordPosted(object sender, JournalRecordEventArgs e)
{
    records.Enqueue(e.Record);

    if (records.Count >= settings.TradeJournalLength)
    {
        recordType temp = null;
        records.TryDequeue(out temp);
    }
}

剩余计算应在锁内进行。否则,它看起来是“线程安全的”。除非它是一个瓶颈,否则我不明白为什么它需要在并发性方面进行“修复”——尽管列表的边界(当用作FIFO时)令人讨厌,因为它涉及许多移动。(也许a会更好;但仍然不涉及并发:D)您只是想保存最近的N个记录吗?例如,您只想保留最后100或1000条记录?Jim-是的,我只需要最后N条记录。user2246674-我将把盈余放在锁中。如果您将盈余计算放在锁中,您所拥有的将起作用。
RemoveRange
是一个O(n)操作,如果调用过多或记录过多,可能会导致瓶颈。您可能希望改为使用循环缓冲区。有一个合理的实现,我每秒有0-5条记录。日志长度约为2000条记录。一旦达到长度。它会在每次调用时删除最旧的记录。这可能需要缩进和解释。