线程与异步循环

Thread vs async loop

提问人:user22844080 提问时间:11/2/2023 最后编辑:Theodor Zouliasuser22844080 更新时间:11/6/2023 访问量:90

问:

我正在尝试将 test1 源代码更改为 test2 源代码。 这两个源代码之间有什么区别吗? 哪种代码效率更高

public class Test1
{
    public static Test1 Instance { get; } = new Test1();
    public event EventHandler EventSomething;

    public Test1()
    {
        Thread thread = new Thread(new ThreadStart(Run));
        thread.IsBackground = true;
        thread.Start();
    }

    void Run()
    {
        while (true)
        {
            Thread.Sleep(5 * 1000);
            EventSomething?.Invoke(this, new EventArgs());
        }
    }
}

public class Test2
{
    public static Test2 Instance { get; } = new Test2();
    public event EventHandler EventSomething;

    public Test2()
    {
        Run();
    }

    async void Run()
    {
        await Task.Delay(5 * 1000);
        EventSomething?.Invoke(this, new EventArgs());
        Run();
    }
}

我不认为有什么区别

C# 多线程 循环 异步

评论

1赞 shingo 11/2/2023
去哪儿了?while (true)
4赞 Alexei Levenkov 11/2/2023
@shingo第二个有“无限递归”而不是无限......while
1赞 Theodor Zoulias 11/2/2023
你想知道 和 之间的区别,或者循环与递归之间的区别吗?你不能同时问两个问题,否则你的问题会太宽泛,并且可能会因为“需要更多关注”而被关闭。Thread.Sleepawait Task.Delay
0赞 user22844080 11/2/2023
我很确定两个代码的结果是相同的。但是,我很好奇哪种代码在硬件使用方面更有效。
0赞 SmellyCat 11/2/2023
就像阿列克谢所写的,前者的结果是一个“无限”循环,后者的结果是“无限”递归。过多的递归将以堆栈溢出而告终。

答:

4赞 JonasH 11/2/2023 #1

两者都不好。

如果你想定期做某事,你应该在大多数情况下使用计时器。这使您的意图更加清晰,您的代码更具可读性。

使用任何计时器时,您需要考虑一些事情。这些也与您的“原型计时器”相关

  1. 使用什么线程(即 UI 线程或后台线程)?
  2. 是否要在间隔内包括执行工作的时间?
  3. 是否存在多次执行重叠的风险?

大多数计时器列表中缺少的是“异步计时器”的新周期计时器,即

while(await myPeriodicTimer.WaitForNextTick()){ // Dispose the timer to exit
    EventSomething?.Invoke(this, new EventArgs());
}

在效率方面,大多数与时序相关的事情都会使用操作系统来执行实际的时序。不同方法之间的开销可能存在差异,但在大多数情况下,这并不重要。如果你真的关心效率,你应该从测量你担心的任何参数开始。只要确保测量正确即可。

0赞 Enigmativity 11/6/2023 #2

我会避免在循环或递归中等待所有时间,并使用某种计时器。

下面是使用 Microsoft 响应式框架的实现:

public class Test2 : IDisposable
{
    public event EventHandler EventSomething;
    
    private IDisposable _subscription;
    
    public Test2()
    {
        _subscription =
            Observable
                .Interval(TimeSpan.FromSeconds(5.0))
                .Subscribe(x => EventSomething?.Invoke(this, new EventArgs()));
    }

    public void Dispose()
    {
        if (_subscription != null)
        {
            _subscription.Dispose();
            _subscription = null;
        }
    }
}

当您完成适当的清理时,只是您的测试类。.Dispose()