Task.Delay是否启动新线程? [英] Does Task.Delay start a new thread?

查看:125
本文介绍了Task.Delay是否启动新线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码(至少在我看来)应创建100个Tasks,它们全部并行等待(这是有关并发的问题,对:D吗?)并几乎同时完成.我想每个Task.Delay对象都会在内部创建一个Timer对象.

The following code should (at least in my opinion) create 100 Tasks, which are all waiting in parallel (that's the point about concurrency, right :D ?) and finish almost at the same time. I guess for every Task.Delay a Timerobject is created internally.

public static async Task MainAsync() {

    var tasks = new List<Task>();
    for (var i = 0; i < 100; i++) {
        Func<Task> func = async () => {
            await Task.Delay(1000);
            Console.WriteLine("Instant");
        };
        tasks.Add(func());
    }
    await Task.WhenAll(tasks);
}

public static void Main(string[] args) {
    MainAsync().Wait();
}

但是!当我在Mono上运行时,我得到非常奇怪的行为:

But! When I run this on Mono I get very strange behavior:

  • Tasks不能同时完成,会有很大的延迟(大约500-600ms)
  • 在控制台中,mono显示了许多已创建的线程:
  • The Tasks do not finish at the same time, there are huge delays (probably about 500-600ms)
  • In the console mono shows a lot of created threads:

已加载的程序集:/Users/xxxxx/Programming/xxxxx/xxxxxxxxxx/bin/Release/xxxxx.exe

Loaded assembly: /Users/xxxxx/Programming/xxxxx/xxxxxxxxxx/bin/Release/xxxxx.exe

线程已启动:#2

线程已启动:#3

线程已启动:#4

线程已启动:#5

线程已启动:#6

线程已启动:#7

线程完成:#3<-显然延迟1000毫秒完成了吗?

Thread finished: #3 <-- Obviously the delay of 1000ms finished ?

线程完成:#2<-显然延迟了1000ms吗?

Thread finished: #2 <-- Obviously the delay of 1000ms finished ?

线程已启动:#8

线程已启动:#9

线程已启动:#10

线程已启动:#11

线程已启动:#12

线程已启动:#13

...明白了.

这实际上是一个错误吗?还是我使用图书馆错误?

Is this actually a bug ? Or do I use the library wrong ?

我使用计时器测试了自定义的睡眠方法:

I tested a custom sleep method using Timer:

    public static async Task MainAsync() {
        Console.WriteLine("Started");
        var tasks = new List<Task>();
        for (var i = 0; i < 100; i++) {
            Func<Task> func = async () => {
                await SleepFast(1000);
                Console.WriteLine("Instant");
            };
            tasks.Add(func());
        }
        await Task.WhenAll(tasks);
        Console.WriteLine("Ready");
    }

    public static Task SleepFast(int amount) {
        var source = new TaskCompletionSource<object>();
        new Timer(state => {
            var oldSrc = (TaskCompletionSource<object>)state;
            oldSrc.SetResult(null);
        }, source, amount, 0);
        return source.Task;
    }

这一次,所有任务立即完成.因此,我认为这是一个非常糟糕的实现或错误.

This time, all tasks completed instantaneously. So, I think it's a really bad implementation or a bug.

[Edit2] 仅供参考:我已经使用Windows 8.1在.NET上测试了原始代码(使用Task.Delay),并且按预期运行(1000 Tasks,并行等待1秒并完成).

Just FYI: I've tested the original code (using Task.Delay) on .NET using Windows 8.1 now and it ran as expected (1000 Tasks, waiting for 1 second in parallel and finishing).

所以答案是:Mono的实现. (某些)方法并不完美.通常,Task.Delay不会启动线程,即使其中很多也不应创建多个线程.

So the answer is: Mono's impl. of (some) methods is not perfect. In general Task.Delay does not start a thread and even a lot of them should not create multiple threads.

推荐答案

Task库设计用于在不阻止整个工作流的情况下管理阻止任务(任务异步性,Microsoft称之为任务并行"),并且不是用于进行大块并行计算(并行执行).

The Task library is designed more for managing blocking tasks without blocking an entire workflow (task asynchronism, confusingly called "task parallel" by Microsoft), and not for doing large blocks of concurrent computation (parallel execution).

任务库使用调度程序,将准备执行的作业排队.运行作业时,它们将在线程池线程上执行,并且这些线程的数量非常有限.有逻辑来增加线程数,但是除非您有数百个CPU内核,否则它将保持在较低的水平.

The task library uses a scheduler and queues jobs ready for execution. When jobs are run, they will do so on a thread-pool thread, and these are very limited in number. There is logic to expand the thread count, but unless you have hundreds of CPU cores, it's going to stay a low number.

为回答这个问题,您的一些任务排队等待来自池中的线程,而其他延迟的任务已由调度程序发出.

So to answer the question, some of your tasks are queued up waiting for a thread from the pool, while the other delayed tasks have been issued by the scheduler.

可以在运行时更改调度程序和线程池逻辑 ,但是如果您试图快速完成大量计算,则Task不适合该工作.如果您要处理大量慢速资源(例如磁盘,数据库或Internet资源),Task可能有助于保持应用程序的响应速度.

The scheduler and thread-pool logic can be changed at runtime, but if you are trying to get lots of computation done quickly Task isn't right for the job. If you want to deal with lots of slow resources (like disk, database, or internet resources) Task may help keep an app responsive.

如果您只想了解Task,请尝试以下操作:

If you just want to learn about Task try these:

  • The Task library
  • The Scheduler

这篇关于Task.Delay是否启动新线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆