我有观察者模块,负责处理我从Kafka创建的一些反应流的订阅。可悲的是,我需要轮询才能接收来自kafka的消息,所以我需要为此专门设置一个后台线程。我的第一个解决方案就是这个:
public void Poll()
{
if (Interlocked.Exchange(ref _state, POLLING) == NOTPOLLING)
{
Task.Run(() =>
{
while (CurrentSubscriptions.Count != 0)
{
_consumer.Poll(TimeSpan.FromSeconds(1));
}
_state = NOTPOLLING;
});
}
}
现在我的评论员建议我Task
,因为它有状态,可以检查它们是否正在运行。这导致了这段代码:
public void Poll()
{
// checks for statuses: WaitingForActivation, WaitingToRun, Running
if (_runningStatuses.Contains(_pollingTask.Status)) return;
_pollingTask.Start(); // this obviously throws exception once Task already completes and then I want to start it again
}
任务几乎保持不变但检查已更改,现在因为我的逻辑是我想在订阅时开始轮询而在我不这样做时停止我需要重新使用任务,但因为我不能,我想知道我是否需要回到我的第一个实现,还是有任何其他简洁的方法来做到这一点,现在我失踪了?
答案 0 :(得分:1)
我想知道我是否需要回到我的第一次实施,还是有任何其他简洁的方法来做到这一点,我现在不见了?
你的第一个实现看起来很好。您可以使用ManualResetEventSlim
代替enum
和Interlocked.Exchange
,但这基本相同......只要您只有两个州。
答案 1 :(得分:0)
我认为我做了一个妥协并删除了MethodImpl(MethodImpl.Options.Synchronized)
的Interlocked API,它让我拥有简单的方法体,而不会让最终新手/没有经验的人混淆Interlocked API代码。
[MethodImpl(MethodImplOptions.Synchronized)]
public void Poll()
{
if (!_polling)
{
_polling = true;
new Task(() =>
{
while (_currentSubscriptions.Count != 0)
{
_consumer.Poll(TimeSpan.FromSeconds(1));
}
_polling = false;
}, TaskCreationOptions.LongRunning).Start();
}
}