我有一个异步方法,它包含一个无止境的while
循环.该循环由程序的主线程频繁暂停和恢复.为此,我目前使用Nito.AsyncEx包中的PauseTokenSource
类:
private readonly PauseTokenSource _pausation = new();
private async Task StartWorker()
{
while (true)
{
await _pausation.Token.WaitWhilePausedAsync();
DoSomething();
}
}
这工作得很好,但我注意到,每次暂停和恢复PauseTokenSource
时,都会分配大约ValueTask
个字节.由于这种情况每秒发生多次,我正在寻找一种方法来消除这种开销.我的 idea 是用一个brew 的暂停机制替换PauseTokenSource
,该机制有一个WaitWhilePausedAsync
方法,返回ValueTask
而不是Task
.为了使实现分配自由,ValueTask
应该由实现IValueTaskSource
接口的东西支持.以下是我当前(失败的)try 实现此机制:
public class Pausation : IValueTaskSource
{
private ManualResetValueTaskSourceCore<bool> _source;
private bool _paused;
public Pausation() => _source.RunContinuationsAsynchronously = true;
public void Pause()
{
_paused = true;
_source.Reset();
}
public void Resume()
{
_paused = false;
_source.SetResult(default);
}
public ValueTask WaitWhilePausedAsync()
{
if (!_paused) return ValueTask.CompletedTask;
return new ValueTask(this, _source.Version);
}
void IValueTaskSource.GetResult(short token)
{
_source.GetResult(token);
}
ValueTaskSourceStatus IValueTaskSource.GetStatus(short token)
{
return _source.GetStatus(token);
}
void IValueTaskSource.OnCompleted(Action<object> continuation, object state,
short token, ValueTaskSourceOnCompletedFlags flags)
{
_source.OnCompleted(continuation, state, token, flags);
}
}
我的Pausation
类基于ManualResetValueTaskSourceCore<T>
struct ,它应该简化最常见的IValueTaskSource
个实现.显然我做错了什么,因为当我的工人await
WaitWhilePausedAsync
方法时,它与InvalidOperationException
崩溃.
My question is:如何修复Pausation
类,使其正常工作?我应该在_paused
字段之外添加更多状态吗?我是不是在错误的地方调用了ManualResetValueTaskSourceCore<T>
个方法?我要的是详细的修复说明,或者是完整的工作实现.
Specifics: Pausation
类旨在用于单工作者-单控制器场景.只有一个异步工作线程(StartWorker
方法),只有一个控制器线程发出Pause
和Resume
条命令.此外,不需要取消支持.辅助进程的终止由CancellationTokenSource
独立处理(为简洁起见,从上述代码段中删除).唯一需要的功能是Pause
、Resume
和WaitWhilePausedAsync
方法.唯一的要求是它工作正常,并且不分配内存.
我的worker-controller场景的可运行在线演示可以在here中找到.
Nito.AsyncEx.PauseTokenSource
类的输出:
Controller loops: 112,748
Worker loops: 84, paused: 36 times
我的Pausation
类的输出:
Controller loops: 117,397
Unhandled exception. System.InvalidOperationException: Operation is not valid due to the current state of the object.
at System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1.GetStatus(Int16 token)
at Program.Pausation.System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(Int16 token)
at Program.<>c__DisplayClass0_0.<<Main>g__StartWorker|0>d.MoveNext()