在我的 razor.cs 文件中,我有以下异步任务,该任务在无限的 while 循环中消耗来自 Kafka 主题的数据。当消费开始时,用户界面被阻止,用户无法离开页面或执行其他操作。我怎样才能防止这种情况发生?我想保留 while 循环。 通常,当用户离开页面时,我想关闭与 Dispose 的连接
我的razor.cs代码:
protected override void OnInitialized()
{
Read_Status_from_Kafka();
}
public async Task Read_Status_from_Kafka()
{
// code for configuring Kafka connection
while (true)
{
//consuming data form Kafka topic
}
}
正如您所发现的,线程[在本例中为同步上下文]一次只能做一件事。您期望的是您可以将其放入监视器循环中并同时响应 UI 事件。
如果您想一直读取数据,那么后台任务是一个很好的解决方案。
如果您只想在页面处于活动状态时读取数据,您可以使用计时器来执行此操作。这将 while 循环的操作“卸载”到计时器,该计时器已经在专用线程上运行这样的循环来处理所有注册的计时器。
这是一个演示页面,它在页面上设置一个计时器每秒运行一次,并在发生变化时更新 UI。
@page "/"
@implements IDisposable
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<div class="bg-dark text-white p-2 m-2">
<pre>@_message</pre>
</div>
@code{
private Timer? _timer;
private string? _message;
private volatile bool _isProcessing; //mark as volatile for thread safely
protected override void OnInitialized()
{
// Kick off the timer on the Timer Service
_timer = new Timer(this.OnTimerExpired, null, 1000, 1000);
}
// Note that this method will be executed on a threadpool thread by the Timer service
// not on the UI thread [synchronisation context]
// isProcesssing ensures we only run one OnTimerExpired at once
private async void OnTimerExpired(object? state)
{
if (_isProcessing)
return;
_isProcessing = true;
//fake Read_Status_from_Kafka();
await Task.Delay(500);
// Update the UI if something has changed
if(true)
{
_message = $"Updated at {DateTime.Now.ToLongTimeString()}";
// invoke the UI update on the UI thread [synchronisation context]
await this.InvokeAsync(StateHasChanged);
}
_isProcessing = false;
}
public void Dispose()
{
_timer?.Dispose();
}
}