简体   繁体   English

带计时器的异步等待

[英]Async await with timer

I am trying to use the Timer to trigger an event to send data across the network.Basically I have a List I'd like to send.我正在尝试使用计时器触发事件以通过网络发送数据。基本上我有一个要发送的列表。 I want the following to happen:我希望发生以下情况:

  1. Add item to List (async) Start Timer for 10 seconds将项目添加到列表(异步)启动计时器 10 秒

  2. Wait for 10 seconds until there another call to add item to list.等待 10 秒,直到再次调用将项目添加到列表。

  3. Add second string to List if there is another call and reset timer.如果有另一个呼叫和重置计时器,则将第二个字符串添加到列表。 Or Else Elapse否则过去

  4. Save all at once after elapse结束后一次性保存

So I have this:所以我有这个:

public class Foo
{
public static List<string> list;
public static Timer timer;
static Foo()
{
    list = new List<string>();
    timer = new Timer(10000);
    timer.Enabled = true;
    timer.AutoReset = false;
    timer.Elapsed += SendToServer;
}

public static async void Log(string value)
{
    list.Add(value);
    timer.Stop();
    timer.Start();
    await Task.Delay(10000);
}

static void SendToServer(object sender, ElapsedEventArgs e)
{
    //TODO send data to server

    //AutoReset is false, so neither of these are needed
    //timer.Enabled = false;
    //timer.Stop();
}
}

This works as expected, however the caller is like这可以按预期工作,但是调用者就像

  1. Foo.log("a"); Foo.log("a");
  2. Foo.log("b"); Foo.log("b");
  3. Foo.Commit(); Foo.Commit(); ---> this method should check if all the Data sent are saved. ---> 这个方法应该检查是否所有发送的数据都保存了。 If not Save the remaining.如果没有保存剩余的。

The issue here is Elapsed event ( SaveToServer) will trigger after Commit.这里的问题是 Elapsed 事件(SaveToServer)将在 Commit 后触发。

Let me know for any resolution or to take another approach.让我知道任何解决方案或采取其他方法。

async void is in almost all situations a bad idea. async void在几乎所有情况下都是一个坏主意。

With your current logic if Log is called, let's say, every 5 seconds you will never send the data to the server.使用您当前的逻辑,如果调用Log ,假设每 5 秒您将永远不会将数据发送到服务器。 This may or may not be what you want.这可能是也可能不是您想要的。

If you want to send in batches every now and the (for example sending logs) I suggest that you separate sending and adding to the list:如果您想每隔一段时间分批发送(例如发送日志),我建议您将发送和添加到列表中分开:

  1. Log just adds to the list - this doesn't need to be async Log只是添加到列表中 - 这不需要是async
  2. Send just sends the content of the list (and clears it in a thread safe way) and is called by some background worker service. Send 只是发送列表的内容(并以线程安全的方式清除它)并由一些后台工作服务调用。

If you want to send 10 after last input you could try something like this:如果您想在最后一次输入后发送 10,您可以尝试以下操作:

// TODO make thread-safe if needed
public class C
{
   private static List<string> list = new();
   private static CancellationTokenSource cts = new ();

   public static void Log(string value)
   {
     list.Add(value);
     cts.Cancel();
     SendToServer();
   }

   static async Task SendToServer()
   {
     try
     {
        await Task.Delay(TimeSpan.FromSeconds(10), cts.Token);
     } 
     catch(TaskCanceledException)
     {
        return;
     }
     // Make a copy, clear `list` send copy to server
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM