【发布时间】:2020-04-24 11:20:13
【问题描述】:
我正在开发一个异步任务处理器。我需要高性能处理器,所以使用的同步原语应该尽可能低级。处理器应该持有一个线程,在没有任务时休眠,在任务出现时唤醒。任务处理和任务添加应该在不同的线程中执行。
我尝试使用AutoResetEvent 实现,但它有竞争条件:
public class Processor
{
ConcurrentQueue<Action> _workItemQueue = new ConcurrentQueue<Action>();
AutoResetEvent _newWorkItemAutoResetEvent = new AutoResetEvent(false);
private bool _disposed;
Thread _thread;
public void Do(Action action)
{
_workItemQueue.Enqueue(action);
_newWorkItemAutoResetEvent.Set();
}
public Processor()
{
_workerThread = new Thread(() =>
{
while (!_disposed)
{
_newWorkItemAutoResetEvent.WaitOne(); //
while (_workItemQueue.TryDequeue(out Action action))
{
action();
}
// at this "bad" moment another thread calls Do method.
// New action has been enqueued, but when we call
// _newWorkIteManualAutoEvent.WaitOne() we fall asleep.
}
});
_thread.Start();
}
}
然后我尝试使用ManualResetEvent:
public class Processor
{
ConcurrentQueue<Action> _workItemQueue = new ConcurrentQueue<Action>();
ManualResetEventSlim _newWorkItemManualResetEvent = new ManualResetEventSlim(false);
private bool _disposed;
Thread _thread;
public void Do(Action action)
{
_workItemQueue.Enqueue(action);
_newWorkItemManualResetEvent.Set();
}
public Processor()
{
_workerThread = new Thread(() =>
{
while (!_disposed)
{
_newWorkItemManualResetEvent.WaitOne();
_newWorkItemManualResetEvent.Reset();
while (_workItemQueue.TryDequeue(out Action action))
{
action();
}
}
});
_thread.Start();
}
}
我没有看到使用 ManualResetEvent 实现的任何竞争条件。
问题:我说的对吗?或者我需要另一个同步原语?我正在考虑 CountupEvent(反向 CountdownEvent)。它在其计数大于零时发出信号,而在其计数等于零时不发出信号。 Countup事件的计数对应于要执行的任务数。
【问题讨论】:
-
关于您想要改进的工作实施的问题必须在codereview提出。
-
“我需要高性能处理器,所以使用的同步原语应该尽可能低级” - 如果性能很重要那你不会使用 C#。 NET 因为 JIT 编译和 GC 引入的延迟。 .NET 的内置异步和线程池功能的性能开销是最小的,并且已经过试验和测试。您自己的代码实际上非常低效,因为您盲目地创建新线程并且线程在 Windows 上很昂贵 - 更不用说您是如何使用
WaitOne()阻塞这些线程的。你为什么不使用线程池? -
这似乎是“并发任务处理器”而不是“异步任务处理器”。
-
@Dai,我只需要 C# 实现,尽可能高性能。在我的实现中,一个处理器只创建一个线程。我不打算创建很多处理器。
-
调用处理器“异步”的问题是它可能会产生错误的期望。如今,“异步”这个词与Task-based asynchronous pattern 密切相关。人们期望处理器返回
Task对象,或接受Func<Task>委托,或两者兼而有之。
标签: c# multithreading asynchronous