关于c#:async-与-Thread-的错误结合

2次阅读

共计 2151 个字符,预计需要花费 6 分钟才能阅读完成。

在 TAP 呈现之前,咱们能够通过 Thread 来实现一些线程操作,从而实现多线程和异步操作。在 TAP 呈现之后,有时候为了更高精度的控制线程,咱们还是会应用到 Thread。文本讲介绍一种谬误的应用形式,作为读者的一个参考。

和 TaskCreateOptions.LongRunning 相似

不应该尝试应用 Thread 执行相似的异步操作。因为这节约了开启线程的花销。

有的时候,你可能会这么写:

var thread = new Thread(async () =>
{while (true)
    {
        // do something
        await Task.Delay(1000);
    }
}){IsBackground = true};
thread.Start();

但其实,这是个谬误的写法。

IDE 提醒

和 TaskCreateOptions.LongRunning 略有不同,采纳这种写法,IDE 会给出一个提醒,表明心愿勾销 async 关键字。因为实际上

  1. Thread 的所有重载中并没有反对 Task 相干的重载。
  2. async void 除了在 event handler 中应用,其余中央都是不举荐的。

所以这种做法实际上并不举荐。

而 TaskFactory.StartNew() 的重载中,因为存在一个 Func<T> 的重载,所以导致尽管这种这种应用形式谬误,却被 IDE 所承受。

所以这里其实就能够总结一个简略的规定: 当考查一组 API 是否原生反对 TAP 操作的时候,应该查看这组 API 中是否存在 Task 相干的重载。如果没有,那么阐明原生并不能良好反对,如果应用则可能会出现意外的状况

同样的,当咱们本人在设计 API 的时候也应该参考该准则,对于本人心愿反对 TAP 的 API,应该提供 Task 相干的重载。

昙花线程

在 thread async void 其实上只是一个很小的问题。这个谬误的要害还是造成了一个昙花线程。

咱们通过以下代码来验证:

var thread = new Thread(async () =>
{while (true)
    {
        // do something
        await Task.Delay(1000);
    }
}){IsBackground = true};
thread.Start();

Thread.Sleep(3000);

Console.WriteLine("thread is alive:" + thread.IsAlive);
// thread is alive: False

这里咱们能够看到,thread.IsAlive 的值为 False。这是因为,咱们在 thread 中应用了 await 关键字,在 await 之后的代码,实际上是在另一个 ThreadPool 中的线程中执行的。而咱们的 thread 自身在 await 之后就曾经完结了。于是咱们就失去了一个过眼云烟的线程。

而这种昙花线程无疑就是一种节约。

如何观测线程的生命周期

其实大体的内容咱们曾经讲完了。但为了凑一下篇幅,咱们着重演示一下如何应用 Rider 来观测线程的生命周期。

首先咱们在 Rider 中创立一个单元测试我的项目,而后在其中创立一个单元测试:

[Test]
public void Test1()
{var t1 = new Thread(async () =>
    {while (true)
        {
            // do something
            await Task.Delay(1000);
        }
    })
    {
        IsBackground = true,
        Name = "t1"
    };
    t1.Start();

    var t2 = new Thread(() =>
    {while (true)
        {
            // do something
            Thread.Sleep(1000);
        }
    })
    {
        IsBackground = true,
        Name = "t2"
    };
    t2.Start();

    Thread.Sleep(3000);
}

而后咱们在 Rider 中依照下图抉择 Profile 选项:

而后抉择 Profile Unit Tests 选项:

稍等片刻之后,咱们就能够双击下图中的报告,来查看线程的生命周期:

在查看界面中,咱们能够通过线程下来框来查看线程运行所破费的工夫:

如果上图,咱们能够很间接的看到,t1 线程的生命周期能够说是霎时就完结了,因为第一次 await 之后,线程就完结了。

总结

在本文中,咱们演示了一种谬误的应用形式,以及如何应用 Rider 来观测线程的生命周期。

参考

  • .NET Task 揭秘(2):Task 的回调执行与 await1
  • Task2
  • TaskCreationOptions3

感谢您的浏览,如果您感觉本文有用,快点击下方点赞按钮👍,让更多的人看到本文。

欢送关注作者的微信公众号“newbe 技术专栏”,获取更多技术内容。

  • 本文作者:newbe36524
  • 本文链接:https://www.newbe.pro/Others/0x027-This-is-the-wrong-way-to-use-LongRunnigTask-in-csharp/
  • 版权申明:本博客所有文章除特地申明外,均采纳 BY-NC-SA 许可协定。转载请注明出处!

  1. https://www.cnblogs.com/eventhorizon/p/15912383.html ↩
  2. https://threads.whuanle.cn/3.task/ ↩
  3. https://learn.microsoft.com/en-us/dotnet/api/system.threading… ↩
正文完
 0