我正在设计一个新的改进的 Logger 组件(.NET 3.5,C#)。
我想使用无锁实现。
日志事件将从(可能)多个线程发送,尽管只有一个线程将实际输出到文件/其他存储介质。
本质上,所有的作者都*将他们的数据排入队列*,以便由其他进程(LogFileWriter)检索。
这可以以无锁的方式实现吗?我在网上找不到对这个特定问题的直接引用。
我正在设计一个新的改进的 Logger 组件(.NET 3.5,C#)。
我想使用无锁实现。
日志事件将从(可能)多个线程发送,尽管只有一个线程将实际输出到文件/其他存储介质。
本质上,所有的作者都*将他们的数据排入队列*,以便由其他进程(LogFileWriter)检索。
这可以以无锁的方式实现吗?我在网上找不到对这个特定问题的直接引用。
如果你发现在这种情况下使用锁太慢了,你的问题就更大了。在我的系统(2.0 GHz Core 2 Quad)上,如果没有争用锁,大约需要 75 纳秒。当然,当它发生争执时,它会花费更长的时间。但是由于锁只是保护对Enqueue
or的调用Dequeue
,日志写入的总时间不太可能超过 75 纳秒。
如果锁是一个问题——也就是说,如果你发现你的线程在那个锁后面排成一行,导致你的应用程序明显变慢——那么建立一个无锁队列不太可能有多大帮助。为什么?因为如果你真的在日志中写了那么多,你的无锁阻塞队列会很快填满,你将受限于 I/O 子系统的速度。
我有一个多线程应用程序,它以每秒 200 个日志条目的顺序写入一个 Queue<string>
受简单锁保护的日志条目。我从未注意到任何重大的锁争用,并且处理速度丝毫没有减慢。75 ns 与执行其他所有操作所需的时间相比相形见绌。
无锁队列的这种实现可能会有所帮助,其中队列是您用于将要出列并由记录器写出的项目排入队列的数据结构。
http://www.boyet.com/Articles/LockfreeQueue.html
您还可以查看 .Net 4 的 ConcurrentQueue
http://www.albahari.com/threading/part5.aspx#_Concurrent_Collections
那里有很多不同的无锁队列实现。
我自己在http://hackcraft.github.com/Ariadne/使用了一种简单的方法,并且是开源的,因此您可以在必要时对其进行调整。
ConcurrerntQueue
也是无锁的,并且可能可以很好地用于大多数目的,尽管在 Ariadne 中有一些成员支持其他操作(例如将整个内容的枚举作为原子操作出队,这允许单个消费者更快地枚举)。