如何仅在指定时间过后才调用方法?

问题描述 投票:0回答:1

当用户执行操作时使用 SignalR 向 UI 发送更新可能会导致频繁调用,我想限制这种情况。我不想在每次发生操作时都发送更新,而是希望仅在自上次操作后经过一定时间后才发送更新。

    private async Task UserSessionUpdated(UserUpdateMessageUpdateCommand auto)
    {
        if (settings.interval is not null && settings.interval.Value > 0)
        {
            _stopwatch ??= new Stopwatch();
            if (_stopwatch.ElapsedMilliseconds > _appSettings.interval.Value ||
                _stopwatch.ElapsedMilliseconds == 0)
            {                   
                await HubContext.Clients.All.SendAsync("UserUpdateMessage", "load");
                _stopwatch.Reset();
                _stopwatch.Start();
                
            }
        }
        else
        {               
            await HubContext.Clients.All.SendAsync("UserUpdateMessage", "load");
        }
    }

    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await Bus.PubSub.SubscribeAsync<UserUpdateMessageUpdateCommand>("", UserSessionUpdated,
            cancellationToken: stoppingToken);
    }

虽然可以选择使用秒表,但它的缺点是即使一天没有任何操作,它也会持续滴答作响。

有没有办法为此目的实现节流机制?有人可以帮助我使用节流来实现这一目标吗?

c# .net-core signalr
1个回答
0
投票

您可以使用

Channel
来实现此目的 - 它们提供有界的要处理的项目队列。它是生产者 - 消费者模式的实现 - 在我们的例子中,我们不希望绑定队列,因此当队列已满时,它将被完全处理。

这是简单的实现,并附有代码解释。您可以使用它作为模板并将您的方法放在适当的位置:

// Sample DTO
public class SignalRMessageDto(DateTime dateTime)
{
    public DateTime DateTime { get; set; } = dateTime;
}

// Create bounded channel, with capacity of 10 items.
// Get the reader and the writer.
var channel = Channel.CreateBounded<SignalRMessageDto>(new BoundedChannelOptions(10));
var reader = channel.Reader;
var writer = channel.Writer;

await WriteMessages();

async Task WriteMessages()
{
    while (true)
    {
        var newMessage = new SignalRMessageDto(DateTime.Now);
        // Try write message - if channel will be at capacity
        // it won't accept new message and we will have
        // information to flush reader.
        var written = writer.TryWrite(newMessage);

        if (written == false)
        {
            Console.WriteLine("Error when writing to channel");
            await FlushReader();
            // Now we should be able to write the message.
            _ = writer.TryWrite(newMessage);
        }
        else
            Console.WriteLine("Successfully written to channel");
        
        await Task.Delay(100);
    }
}

async Task FlushReader()
{
    Console.WriteLine("Flushing reader!");
    // We read and process all messages in channel.
    await foreach (var item in reader.ReadAllAsync())
    {
        Console.WriteLine(item.DateTime);
        // If we emptied channel, break.
        if (reader.Count == 0) break;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.