【问题标题】:Logging from Multiple Threads, .NET 4从多线程记录,.NET 4
【发布时间】:2013-06-29 03:46:44
【问题描述】:

我有 JournalService 类,它收集事件的记录。该类在列表中收集记录。事件来自多个线程。记录列表长度有限制。我正在使用.NET 4.0。 为了使其线程安全,我锁定了对“记录”列表的读写访问。 我在这件事上没有经验,我不确定我做得很好。 可能我必须使用System.Collections.Concurrent Namespace

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

目前的代码是:

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

EDIT:剩余计算放在锁内。 编辑:添加了对 surplus == 0 的检查。

【问题讨论】:

  • 盈余计算应该在锁内部完成。否则它会出现在“线程安全”中。除非它是一个瓶颈,否则我不明白为什么在并发方面需要“修复”它 - 尽管 List 的边界(当用作 FIFO 时)是 icky,因为它涉及许多移动。 (也许Queue 会更好;但仍然不涉及并发:D)
  • 您只是想保留最近的 N 条记录吗?例如,您只想保留最后 100 条或 1,000 条记录?
  • Jim - 是的,我只需要最后 N 条记录。 user2246674 - 我会把剩余的锁起来。
  • 只要你把剩余的计算放在锁里,你所拥有的就会起作用。 RemoveRange 是一个 O(n) 操作,如果您经常调用它或有大量记录,可能会导致瓶颈。您可能想改用循环缓冲区。 circularbuffer.codeplex.com/SourceControl/latest#CircularBuffer/… 有一个合理的实现
  • 我每秒有 0-5 条记录。期刊长度约为 2000 条记录。一旦达到长度。它会在每次通话时删除最旧的记录。

标签: c# .net multithreading concurrency


【解决方案1】:

您可以使用 无锁并发队列

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

【讨论】:

  • 这可以使用缩进和解释。
【解决方案2】:

使用并发队列:

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

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

【讨论】:

    猜你喜欢
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多