异步似乎是同步的

时间:2019-12-09 08:37:33

标签: c# asynchronous async-await

我不确定我是否在这里丢失了一些东西,但是更多的for循环似乎正在同步执行,即使我正在等待它之外的所有任务。

以下是我的代码:

static void Main(string[] args) {
    var t = Start();
}

public static async Task < List < Task < TaskInfo >>> Start() {
    var listOfTasks = new List < Task < TaskInfo >> ();
    for (var i = 0; i <= 100; i++) {
        var process = new Processor();
        listOfTasks.Add(process.Process(i));
    }

    await Task.WhenAll(listOfTasks);
    return listOfTasks;
}

我传递taskId登出只是为了查看任务执行的顺序。

我在这里真的缺少明显的东西吗?

编辑:

已根据下面的答案和注释将代码更改为该代码,但仍会同步出现:

    public class StartWork
{
    public int TaskId { get; set; }
    public Processor Processor { get;}

    public StartWork()
    {
        Processor = new Processor();
    }
}

    static void Main(string[] args)
    {
        var t = Start();
    }

    public static async Task<TaskInfo[]> Start()
    {
        var tasks = new List<StartWork>();

        for (int i = 1; i < 100; i++)
        {
            var work = new StartWork
            {
                TaskId = i
            };
            tasks.Add(work);
        }

        return await Task.WhenAll(tasks.Select(i => i.Processor.Process(i.TaskId)));
    }

我在处理器类中调用的函数:

 public Task<TaskInfo> Process(int taskId)
    {
        try
        {
            taskId = taskId + 1;
            stopwatch.Start();
            using (var bus = RabbitHutch.CreateBus(xxDev))
            {
                @event = new AutoResetEvent(false);

                var replyTo = Guid.NewGuid().ToString();
                var messageQueue = bus.Advanced.QueueDeclare(replyTo, autoDelete: true);

                bus.Advanced.Consume(messageQueue, (payload, properties, info) =>
                {
                    ReceivePdf(payload, properties, info);
                    return Task.FromResult(0);
                });

                taskInfo.InputFile = inputFile;
                var html = File.ReadAllText(inputFile);
                taskInfo.Html = html;

                var message = PrepareMessage(new RenderRequest()
                {
                    Html = Encoding.UTF8.GetBytes(html),
                    Options = new RenderRequestOptions()
                    {
                        PageSize = "A4",
                        ImageQuality = 70,
                        PageLoadRetryAttempts = 3
                    }
                });

                var correlation = Guid.NewGuid().ToString();
                Console.WriteLine($"CorrelationId: {correlation}, TaskId {taskId}");

                var props = new MessageProperties
                {
                    CorrelationId = correlation,
                    ReplyTo = replyTo,
                    Expiration = "6000"
                };

                Publish(bus, props, message);
                taskInfo.CorrelationId = Guid.Parse(correlation);
                @event.WaitOne();
                stopwatch.Stop();
                taskInfo.TimeTaken = stopwatch.Elapsed;
                return Task.FromResult(taskInfo);
            }
        }
        catch (Exception e)
        {
            taskInfo.OutputFile = Empty;
            return Task.FromResult(taskInfo);
        }
    }

        void ReceivePdf(byte[] payload, MessageProperties properties, MessageReceivedInfo info)
    {
        var file = Format(outputFile, properties.CorrelationId);
        taskInfo.OutputFile = file;

        Console.WriteLine("Output written to " + file);

        File.WriteAllBytes(file, payload);

        var remaining = Interlocked.Decrement(ref outstandingRequests);

        if (remaining == 0)
        {
            @event.Set();
        }
    }

2 个答案:

答案 0 :(得分:1)

这是一个同步任务

listOfTasks.Add(process.Process(i));

您只是将项目添加到列表中。

这也是同步任务

process.Process(i);

上面的函数返回的任务是异步的,它将在代码的whenAll调用中异步执行。

请记住,当所有人都将等待所有任务运行时,并且如果任务很琐碎,则由于它们一个接一个地启动,因此大多数情况下会偶然运行。

如果执行的任务代码根据输入的执行时间而有所不同,您会看到一些区别。

答案 1 :(得分:0)

第一个异步并不意味着多线程,异步用于运行后台任务而不阻塞UI或运行I / O操作而不会阻塞主线程。 通常,操作系统使用多线程处理异步,但是并不能保证。 如果您要确保启动多个线程,请使用Thread.Start。

无论如何,您都必须强制代码同步运行,因为您无需等待即可在Main方法中调用async方法start。

您需要将代码更改为:

static async void Main(string[] args)
{
   var t = await Start();
}

或不等待(但程序有在任务完成前终止的风险):

static void Main(string[] args)
{
   Task.Run(async () => {
       var t = await Start();
   });
}