c# - 使用 Tasks (TPL) 库会使应用程序多线程吗?

标签 c# multithreading .net-4.0 task-parallel-library multitasking

最近在接受采访时,我被问到了这个问题。

问:你写过多线程应用程序吗?

答:是的

问:介意解释更多吗?

答:我用过 Tasks (任务并行库)执行一些任务,如 waiting for some info from internet while loading UI .这提高了我的应用程序可用性。

问:但是,刚刚你用过 TPL表示您写了一个 multithreaded应用?

我:(不知道说什么1)

那么,究竟什么是多线程应用程序?和用Tasks有区别吗?

最佳答案

任务可用于表示在多个线程上发生的操作,但它们不是必须的。可以编写仅在单个线程中执行的复杂 TPL 应用程序。例如,当您有一个任务代表对某些数据的网络请求时,该任务不会创建额外的线程来实现该目标。这样的程序(希望)是异步的,但不一定是多线程的。

并行是同时做不止一件事。这可能是也可能不是多线程的结果。

让我们在这里打个比方。

这是鲍勃做饭的方式:

  • 他装满一壶水,煮沸。
  • 然后他将意大利面放入水中。
  • 完成后,他将意大利面沥干。
  • 他为他的酱汁准备配料。
  • 他把他的酱汁的所有原料放在一个平底锅里。
  • 他煮他的酱汁。
  • 他把他的酱汁放在他的意大利面上。
  • 他吃晚饭。

  • Bob 在 cooking 晚餐时完全同步 cooking ,没有多线程、异步或并行。

    这是简做晚饭的方式:
  • 她装满一壶水并开始煮沸。
  • 她准备酱汁的配料。
  • 她将意大利面放入沸水中。
  • 她把配料放进平底锅里。
  • 她沥干她的意大利面。
  • 她把酱汁放在她的意大利面上。
  • 她吃她的晚餐。

  • Jane 在做饭时利用异步 cooking (没有任何多线程)来实现并行性。

    以下是 Servy cooking 晚餐的方式:
  • 他告诉鲍勃煮一壶水,准备好后放入意大利面,然后端上意大利面。
  • 他告诉简准备酱汁的原料,煮熟,然后在完成后把它放在意大利面上。
  • 他等待鲍勃和简完成。
  • 他吃他的晚餐。

  • Servy 利用了多个线程(worker),每个线程都单独同步工作,但彼此之间异步工作以实现并行性。

    当然,如果我们考虑例如我们的炉子是有两个燃烧器还是只有一个燃烧器,这会变得更加有趣。如果我们的炉子有两个燃烧器,那么我们的两个线程 Bob 和 Jane 都能够在不妨碍彼此的情况下完成他们的工作。他们可能会撞到肩膀,或者每个人都时不时地尝试从同一个柜子里拿东西,所以他们每个人都会放慢一点,但不会太多。如果他们每个人都需要共用一个炉子燃烧器,那么当另一个人正在工作时,他们实际上根本无法完成很多工作。在这种情况下,工作实际上不会比让一个人完全同步做饭更快,就像鲍勃独自一人时所做的那样。在这种情况下,我们使用多个线程进行 cooking ,但我们的 cooking 不是并行化的。并非所有多线程工作实际上都是并行工作。当您在具有一个 CPU 的机器上运行多个线程时会发生这种情况。您实际上并没有比使用一个线程更快地完成工作,因为每个线程只是轮流工作。 (这并不意味着多线程程序在单核 CPU 上毫无意义,它们不是,只是使用它们的原因不是为了提高速度。)

    我们甚至可以考虑这些厨师将如何使用任务并行库来完成他们的工作,以了解 TPL 的哪些用途对应于这些类型的厨师中的每一种:

    所以首先我们有 bob,只需编写普通的非 TPL 代码并同步执行所有操作:
    public class Bob : ICook
    {
        public IMeal Cook()
        {
            Pasta pasta = PastaCookingOperations.MakePasta();
            Sauce sauce = PastaCookingOperations.MakeSauce();
            return PastaCookingOperations.Combine(pasta, sauce);
        }
    }
    

    然后我们有 Jane,她启动了两个不同的异步操作,然后在启动每个异步操作后等待这两个操作来计算她的结果。
    public class Jane : ICook
    {
        public IMeal Cook()
        {
            Task<Pasta> pastaTask = PastaCookingOperations.MakePastaAsync();
            Task<Sauce> sauceTask = PastaCookingOperations.MakeSauceAsync();
            return PastaCookingOperations.Combine(pastaTask.Result, sauceTask.Result);
        }
    }
    

    在此提醒一下,Jane 正在使用 TPL,并且她正在并行执行她的大部分工作,但她只使用一个线程来完成她的工作。

    然后我们有 Servy,他使用 Task.Run创建一个代表在另一个线程中工作的任务。他启动了两个不同的 worker,让它们每个都同步做一些工作,然后等待两个 worker 完成。
    public class Servy : ICook
    {
        public IMeal Cook()
        {
            var bobsWork = Task.Run(() => PastaCookingOperations.MakePasta());
            var janesWork = Task.Run(() => PastaCookingOperations.MakeSauce());
            return PastaCookingOperations.Combine(bobsWork.Result, janesWork.Result);
        }
    }
    

    关于c# - 使用 Tasks (TPL) 库会使应用程序多线程吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23833255/

    相关文章:

    c# - 如何知道应用程序导航到HomeActivity或LoginActivity - Appium

    python - 与 select 进行线程间通信的干净方式

    visual-studio-2010 - 适用于 .NET 4.0 的 FxCop

    c# - ASP.NET 身份验证票过期问题

    c# - 更改 Windows 键盘输入语言时应用程序卡住

    c# - 如何在类库项目中配置自动映射器?

    c# - 无需挂起即可访问 UI

    multithreading - Rust 中大量线程的性能下降

    java - 线程中的异常 java.lang.NullPointerException

    c# - 触发内容模板