Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步操作的循环调用模式_C#_Event Handling_Task - Fatal编程技术网

C# 异步操作的循环调用模式

C# 异步操作的循环调用模式,c#,event-handling,task,C#,Event Handling,Task,我想定期执行一些基于I/O的异步操作。 它不应该运行得尽可能快,而是在两个周期之间有一个可配置的延迟 到目前为止,我提出了两种不同的方法,我想知道哪一种在资源消费方面更好 使用Task.Run()接近1 用这种方法包装在Task.Run()中是不必要的,但是这样更好吗 我为这两种方法创建了一个.Net控制台应用程序,并在几分钟内记录了以下性能计数器,老实说,没有看到太大的差异: \处理(事件)%处理器时间(接近高出2~20%) \进程(事件)\Private字节(几乎相等,接近2 slighlt

我想定期执行一些基于I/O的异步操作。 它不应该运行得尽可能快,而是在两个周期之间有一个可配置的延迟

到目前为止,我提出了两种不同的方法,我想知道哪一种在资源消费方面更好

使用Task.Run()接近1

用这种方法包装在
Task.Run()
中是不必要的,但是这样更好吗

我为这两种方法创建了一个.Net控制台应用程序,并在几分钟内记录了以下性能计数器,老实说,没有看到太大的差异:

  • \处理(事件)%处理器时间(接近高出2~20%)
  • \进程(事件)\Private字节(几乎相等,接近2 slighlty 下)
  • \进程(事件)\n线程计数(接近2~25%的降低)
  • 当前逻辑线程的.NET CLR锁和线程(事件)# (几乎相等,接近2略高)
  • 当前物理线程的.NET CLR锁和线程(事件)# (几乎相等,接近2略高)
  • .NET CLR锁和线程(事件)\n争用率/秒(方法2 约高出50%)

  • 使用这些计数器时,我是否忽略了要点?

    这两个计数器实际上在做相同的事情。事件选项似乎增加了不必要的复杂性。资源消耗差异不显著

    更合适的选择是使用or。这使得代码更容易阅读和理解,因为它表达了意图。在幕后,所有的备选方案或多或少都会产生相同的结果


    你需要考虑一下你是如何计算时间的。执行时间是否应包含在计时间隔中?通常间隔比执行时间长得多,所以这无关紧要。如果有关系,您可能需要将计时器设置为仅触发一次,并在操作完成后设置计时器。

    根据公认的答案,以下是我的新方法:

     internal class EventHandlerService
        {
            private Timer _timer;
            private TimeSpan refreshTime = TimeSpan.FromSeconds(5);
    
            public void Start()
            {           
                _timer = new Timer(Communicate, null, 0,(int)refreshTime.TotalMilliseconds);
            }
    
            private void Communicate(object stateInfo)
            {
                Task.Run(async () =>
                {
                    _timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); // stop the timer
                    Console.WriteLine($"Starting at {DateTime.UtcNow.ToString("O")}");
                    var stopWatch=new Stopwatch();
                    stopWatch.Start();
                    try
                    {
                        await Task.Delay(TimeSpan.FromSeconds(1));
                    }
                    catch (Exception ex)
                    {
                    }
                    finally
                    {
                        Console.WriteLine($"Finishing at {DateTime.UtcNow.ToString("O")} after: {stopWatch.Elapsed}");
                        var dueTime = refreshTime.Subtract(stopWatch.Elapsed);
                        Console.WriteLine($"Calced dueTime to: {dueTime.TotalSeconds} at {DateTime.UtcNow.ToString("O")}");
    
                        _timer.Change(Math.Max((int) dueTime.TotalMilliseconds, 0), (int)refreshTime.TotalMilliseconds); // start the timer
                    }
                });
            }
    
          
        }
    
    通过这种方法,我满足了自己的需求:
    实际刷新/计时器周期从不低于5秒,但如果处理程序的时间超过5秒,则会立即触发下一次执行。

    唯一的问题是:如果事件处理程序的时间超过间隔时间,则我不想“排队”我的事件处理程序,而只是立即触发下一次执行。应该承认,在一个处理器上只有一个on处理程序time@yBother然后使用threading.Timer并在每次任务完成时调用
    .Change
    ,无限期。另一种选择是一个简单的循环,它启动您的工作并调用
    任务。延迟
    ,这比伪递归任务更具可读性。我找不到使线程化的方法。计时器只触发一次?@yBother阅读
    的文档。更改
    “期间。。。指定System.Threading.InfinitieTimeSpan以禁用周期信号“即-1。
     internal class CommunicationService
        {
            private event EventHandler CommunicationHandler;
            private readonly HttpClient _httpClient = new HttpClient(new HttpClientHandler());
    
            public void Start()
            {
                CommunicationHandler = (o, events) => Communicate();
                OnCommunicationTriggered();
            }
    
            private async void Communicate()
            {
                try
                {
                    var result = await _httpClient.GetAsync(someUri);
                    await Task.Delay(TimeSpan.FromSeconds(configurableValue));
    
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex);
                    OnCommunicationTriggered();
                }
                OnCommunicationTriggered();
            }
    
            private void OnCommunicationTriggered()
            {
                CommunicationHandler.Invoke(this, EventArgs.Empty);
            }
        }
    
     internal class EventHandlerService
        {
            private Timer _timer;
            private TimeSpan refreshTime = TimeSpan.FromSeconds(5);
    
            public void Start()
            {           
                _timer = new Timer(Communicate, null, 0,(int)refreshTime.TotalMilliseconds);
            }
    
            private void Communicate(object stateInfo)
            {
                Task.Run(async () =>
                {
                    _timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); // stop the timer
                    Console.WriteLine($"Starting at {DateTime.UtcNow.ToString("O")}");
                    var stopWatch=new Stopwatch();
                    stopWatch.Start();
                    try
                    {
                        await Task.Delay(TimeSpan.FromSeconds(1));
                    }
                    catch (Exception ex)
                    {
                    }
                    finally
                    {
                        Console.WriteLine($"Finishing at {DateTime.UtcNow.ToString("O")} after: {stopWatch.Elapsed}");
                        var dueTime = refreshTime.Subtract(stopWatch.Elapsed);
                        Console.WriteLine($"Calced dueTime to: {dueTime.TotalSeconds} at {DateTime.UtcNow.ToString("O")}");
    
                        _timer.Change(Math.Max((int) dueTime.TotalMilliseconds, 0), (int)refreshTime.TotalMilliseconds); // start the timer
                    }
                });
            }
    
          
        }