首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何按顺序而不是并行地等待C#任务?

如何按顺序而不是并行地等待C#任务?
EN

Stack Overflow用户
提问于 2021-10-04 21:41:18
回答 5查看 660关注 0票数 2

我有一组异步测试,它们运行在外部硬件上。

我可以按顺序运行它们,但是由于所有这些测试都有副作用,我希望能够对它们进行洗牌,并反复运行它们。

当我将它们放到列表中,然后尝试等待它们之后,它们都会并行运行,而不是一一对应地运行。

我希望能够洗牌,然后按顺序运行它们。

如何将测试(**List<Task<bool>**)按顺序运行,同时将它们保存在列表中,以便对列表进行洗牌?

代码语言:javascript
复制
private async void RunVisca()
{
    Ptz ptz = new Ptz(SelectedComPort, (byte)(1), SelectedBaudRate, Node.DeviceType.PTZ);

    UpdateResults("VISCA TEST START\n\n");

    // Method 1: Correct - Runs in order
    await VTestDriveClosedLoop(ptz, true);
    await VTestDriveClosedLoop(ptz, false);
    await VTestLimitsCl(ptz, 125, 20);
    await VTestLimitsOl(ptz, 125, 20);

    // Method 2: Incorrect - Runs in parallel
    List<Task<bool>> tests = new List<Task<bool>>();
    tests.Add(VTestDriveClosedLoop(ptz, true));
    tests.Add(VTestDriveClosedLoop(ptz, false));
    tests.Add(VTestLimitsCl(ptz, 125, 20));
    tests.Add(VTestLimitsOl(ptz, 125, 20));

    // Tasks all run in parallel here - should they not run in order?
    foreach(Task<bool> test in tests)
    {
        _ = await test.ConfigureAwait(true);
    }

    UpdateResults("\nTEST COMPLETE\n\n");
}
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2021-10-04 21:58:58

基于任务的异步模式意味着调用一个返回Taskasync方法将返回一个热门任务。

处于热状态的Task已经启动。可以通过检查Task.Status属性来证明这一点,它永远不会是TaskStatus.Created

冷任务将具有Task.Status属性TaskStatus.Created &只有在实例上调用Start()时才会开始运行。

创建冷任务的唯一方法是使用Task/Task<T>各自的公共构造函数。

因为您的任务是由异步方法返回的,所以当它们返回给您时,它们已经在运行。

要按顺序运行它们&而不是并行运行,必须先完成之前的任务,否则不能彼此创建它们。为了确保这一点,您必须分别对它们进行await

的结果是方法1是按顺序运行热任务的正确方法&而不是并行的.

代码语言:javascript
复制
await VTestDriveClosedLoop(ptz, true);
await VTestDriveClosedLoop(ptz, false);
await VTestLimitsCl(ptz, 125, 20);
await VTestLimitsOl(ptz, 125, 20);

方法2/3不正确,因为它将并行运行您的任务。

您正在将从async方法返回的热任务添加到列表中,而无需等待它们。在您继续将下一个任务添加到列表之前,它们将已经开始运行。

第一个任务是,不等待,所以第二个任务将立即开始,不管任务1是否完成。

第二项任务没有等待,所以第三项任务等等。

使用方法2/3,它们将始终并行运行。

代码语言:javascript
复制
tests.Add(VTestDriveClosedLoop(ptz, true));
tests.Add(VTestDriveClosedLoop(ptz, false));

真正的问题是如何按照顺序运行冷任务,这样我们就可以将它们存储在列表中,同时利用延迟执行的优势,直到我们遍历列表。

解决方案是存储委托,而不是存储,这将触发以下任务构造函数:

public Task (Func<TResult> function);

这将创建冷任务,让您在调用Task时运行Func<Task<bool>>

代码语言:javascript
复制
var tests = new List<Func<Task<bool>>>();
tests.Add(() => VTestDriveClosedLoop(ptz, true));
tests.Add(() => VTestDriveClosedLoop(ptz, false));
tests.Add(() => VTestLimitsCl(ptz, 125, 20));
tests.Add(() => VTestLimitsOl(ptz, 125, 20));
    
foreach (var test in tests) {
     await test();
}

下面这个演示程序将清楚地显示按顺序运行的任务与并行任务。

代码语言:javascript
复制
class Program
{
    private static async Task Main(string[] args)
    {
        // 1... 2... 3... 4...
        var tasksThatRunInOrder = new List<Func<Task<bool>>>();
        tasksThatRunInOrder.Add(() => Test("1"));
        tasksThatRunInOrder.Add(() => Test("2"));
        tasksThatRunInOrder.Add(() => Test("3"));
        tasksThatRunInOrder.Add(() => Test("4"));

        foreach (var test in tasksThatRunInOrder)
            await test();

        // 1, 2, 3, 4
        var testsThatRunInParallel = new List<Task<bool>>();
        testsThatRunInParallel.Add(Test("1"));
        testsThatRunInParallel.Add(Test("2"));
        testsThatRunInParallel.Add(Test("3"));
        testsThatRunInParallel.Add(Test("4"));

        foreach (var test in testsThatRunInParallel)
            await test;
    }

    private static async Task<bool> Test(string x)
    {
        Console.WriteLine(x);
        await Task.Delay(1000);
        return true;
    }
}
票数 5
EN

Stack Overflow用户

发布于 2021-10-04 22:53:35

任务在创建时开始。因为您是同时创建所有这些,而不需要等待它们中的任何一个,所以它们将以一种尚未确定的并行方式执行。我想也许你想要储存代表。在调用之前不会执行这些操作。

代码语言:javascript
复制
var tests = new List<Func<Task<bool>>>();
tests.Add( () => VTestDriveClosedLoop(ptz, true) );
tests.Add( () => VTestDriveClosedLoop(ptz, false) );
tests.Add( () => VTestLimitsCl(ptz, 125, 20) );
tests.Add( () => VTestLimitsOl(ptz, 125, 20) );
    
foreach(var test in tests)
{
    _ = await test(); 
}
票数 2
EN

Stack Overflow用户

发布于 2021-10-04 21:47:58

您可以创建一个列表,在该列表中,您将要运行的顺序随机化,然后调用相应创建任务的函数。例如:

代码语言:javascript
复制
    static async Task RunTasks()
    {
        Random rng = new Random();
        var order = new List<int>() { 1, 2 };
        var shuffledOrder = order.OrderBy(a => rng.Next()).ToList();

        foreach (var i in shuffledOrder)
        {
            switch (i)
            {
            case 1:
                await LoadFile1();
                break;
            case 2:
                await LoadFile2();
                break;
            }
        }
    }
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69442685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档