简体   繁体   English

任务相互等待完成

[英]Tasks wait for each other to complete

I'm creating a Selenium bot as a WPF application.我正在创建一个 Selenium 机器人作为 WPF 应用程序。 I'm using Tasks to create bots and then tasks to perform things on bot.我正在使用任务来创建机器人,然后使用任务在机器人上执行任务。

        foreach (string account in accounts)
        {
            count++;

            _ = Task.Run(async () =>
            {
                Bot bot = new Bot();

               //here is long code for what should bot do ASYNC

               //example
                await bot.Connect();                   
                await bot.SendTokens(); 
                await bot.SayHi(); 
            });
            await Task.Delay(600);
        }

I have array of accounts and I loop through them.我有一系列帐户,我遍历它们。

Let's say accounts.Length = 10 => I want to create 10 tasks that will 'have their own life' and run async inside of them.假设accounts.Length = 10 => 我想创建 10 个“拥有自己的生活”并在其中运行异步的任务。 My problem is that Tasks wait for each other.我的问题是任务相互等待。 Loop will create 10 tasks gradually (because of Task.Delay(600) ) => Bot will be created and start bot.Connect(); Loop 将逐渐创建 10 个任务(因为Task.Delay(600) )=> Bot 将被创建并启动bot.Connect(); Lets say it takes always same amount of time to complete Connect() .可以说完成Connect()总是需要相同的时间。

Logically first Task should be completed 600ms faster than second Task.从逻辑上讲,第一个任务应该比第二个任务快 600 毫秒。 Problem is that program waits until all Connect() are completed.问题是程序一直等到所有Connect()都完成。 Then it starts gradually all SendTokens() then complete them, but first task won't start SayHi() until SendTokens() of last bot in list is completed.然后它逐渐启动所有SendTokens()然后完成它们,但第一个任务不会启动SayHi()直到列表中最后一个机器人的SendTokens()完成。

Why is that happening, I don't understand that.为什么会这样,我不明白。 I tried setting我试过设置

ThreadPool.SetMaxThreads(500, 500);

but that does nothing for me.但这对我没有任何帮助。

Here is example of live debug output, starts LoadOptions() gradually many times, but first LoadOptions() should be already completed and next method should be already started but it is waiting for all LoadOptions to end.这是实时调试输出的示例,逐步启动LoadOptions()多次,但第一个LoadOptions()应该已经完成​​,下一个方法应该已经启动,但它正在等待所有LoadOptions结束。 I don't use in code Task.WaitAll() .我不在代码Task.WaitAll()中使用。

调试输出

Can anyone help me fix this issue and tell me what was wrong?谁能帮我解决这个问题并告诉我出了什么问题? I want to learn and know in future.我想在未来学习和了解。 Thank you very much and have a nice day.非常感谢,祝您有愉快的一天。

As I understand it, your loop launches N bots and starts them on a "Life of their own" .据我了解,您的循环会启动 N 个机器人并以“自己的生活”启动它们。 The loop provides a spacing of 600 ms between Bot launches.该循环在Bot启动之间提供 600 毫秒的间隔。 The Bot class contains various async tasks, and for any given Bot there is an example start sequence of Connect , SendTokens , and SayHi where each of these three methods must complete before the next one starts. Bot类包含各种async任务,对于任何给定的Bot ,都有一个ConnectSendTokensSayHi的示例启动序列,其中这三个方法中的每一个都必须在下一个方法开始之前完成。

But apart from that, each bot should be taking care of its own internal tasks concurrently while other bots are taking care of theirs.但除此之外,每个机器人应该同时处理自己的内部任务,而其他机器人则在处理它们的内部任务。 A typical concurrent timeline might look like this:典型的并发时间线可能如下所示:

并发时间线

Here's one approach you could try to achieve this outcome.这是您可以尝试实现此结果的一种方法。 If the Bot class comes from a library where it can't be modified you can still make an async Extension method for it instead.如果Bot类来自无法修改的库,您仍然可以为其创建async扩展方法。 (I'll show it that way just in case. Otherwise just make it a normal method of the Bot class.) Note that the return type is void ; (以防万一,我会以这种方式显示。否则,只需将其Bot类的普通方法。)请注意,返回类型是void the Bot has a life of its own per your post!根据您的帖子, Bot有自己的生命! We don't wait for it to live its life.我们不会等待它过上它的生活。 HOWEVER it has internal business where one async activity must run to completion before the next one starts, and this extension method accounts for that.然而,它有内部业务,其中一个async活动必须在下一个活动开始之前运行完成,而这种扩展方法说明了这一点。

static class Extensions
{
    public static async void PostInitAsyncRequest(this BlackBoxBot bot)
    {
        await bot.Connect();
        await bot.SendTokens();
        await bot.SayHi();
    }
}

All your WPF application needs to do is call the launchAllBots method which waits 600 ms between launches.您的WPF应用程序需要做的就是调用launchAllBots方法,该方法在两次启动之间等待 600 毫秒。

async void launchAllBots() 
{
    foreach (string account in new string[] 
    {"Jessie", "Ross", "Kensho", "Ernest", "Amy", "Andrew", "Baxter", "Jibo", "Buddy"})
    { 
        // Has its own life so DO NOT AWAIT
        var bot = new BlackBoxBot();
        bot.Account = account;
        bot.PostInitAsyncRequest();

        // But DO await the delay to space out Bot launches
        await Task.Delay(600);          
    }
}

SIMULATION In order to mock this startup timeline, the following fake Bot class was used:模拟为了模拟这个启动时间线,使用了以下假Bot类:

// A crude mock of the 'Bot' class with internal async methods.
class BlackBoxBot
{
    public async Task Connect() 
    {
        Console.WriteLine($"{DateTime.Now.ToString("ss:fff")} {Account}: {nameof(Connect)}");
        await Task.Delay(_rando.Next(400, 800));
    }
    public async Task SendTokens()
    {
        Console.WriteLine($"{DateTime.Now.ToString("ss:fff")} {Account}: {nameof(SendTokens)}");
        await Task.Delay(_rando.Next(400, 800));
    }
    public async Task SayHi()
    {
        Console.WriteLine($"{DateTime.Now.ToString("ss:fff")} {Account}: {nameof(SayHi)}");
        await Task.Delay(_rando.Next(400, 800));
    }

    static Random _rando = new Random();

    public string Account { get; internal set; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM