C# 等待任务不等待

C# 等待任务不等待,c#,asynchronous,task,C#,Asynchronous,Task,我有一个简单的MS文档形式的通用油门功能的实现 public async Task RunTasks(List<Task> actions, int maxThreads) { var queue = new ConcurrentQueue<Task>(actions); var tasks = new List<Task>(); for (int n = 0; n < maxThreads; n

我有一个简单的MS文档形式的通用油门功能的实现

 public async Task RunTasks(List<Task> actions, int maxThreads)
    {
        var queue = new ConcurrentQueue<Task>(actions);
        var tasks = new List<Task>();
        for (int n = 0; n < maxThreads; n++)
        {
            tasks.Add(Task.Run(async () =>
            {
                while (queue.TryDequeue(out Task action))
                {
                    action.Start();
                    await action;
                    int i = 9; //this should not be reached.
                }
            }));
        }
        await Task.WhenAll(tasks);
    }
public异步任务RunTasks(列出操作,int-maxThreads)
{
var队列=新的ConcurrentQueue(操作);
var tasks=新列表();
对于(int n=0;n
{
while(queue.TryDequeue(out任务操作))
{
action.Start();
等待行动;
int i=9;//不应达到此值。
}
}));
}
等待任务。何时(任务);
}
要测试它,我有一个单元测试:

 [Fact]
    public async Task TaskRunningLogicThrottles1()
    {
        var tasks = new List<Task>();
        const int limit = 2;

        for (int i = 0; i < 2000; i++)
        {
            var task = new Task(async () => {
                await Task.Delay(-1);
            });
            tasks.Add(task);
        }
        await _logic.RunTasks(tasks, limit);
    }
[事实]
公共异步任务TaskRunningLogicThrottles1()
{
var tasks=新列表();
常数int极限=2;
对于(int i=0;i<2000;i++)
{
var task=新任务(异步()=>{
等待任务。延迟(-1);
});
任务。添加(任务);
}
等待逻辑。运行任务(任务,限制);
}

由于任务中存在延迟(-1),因此该测试不应完成。永远不能到达RunTasks函数中的“int y=9;”行。然而,它确实做到了,而我的整个函数并没有做到它应该做的事情——节流执行。如果我使用的是synchronous Thread.Sleep ot,而不是Wait Task.Delay()。

Task类没有接受异步委托的对象,因此传递给它的异步委托是。这是一个常见的陷阱。仅仅因为编译器允许我们向任何lambda添加
async
关键字,并不意味着我们应该这样做。我们应该只将异步lambda传递给期望并理解它们的方法,这意味着参数的类型应该是带有
Task
返回值的。例如
Func
,或
Func
,或
Func

您可以做的是将异步lambda传递给
Task
构造函数,在这种情况下
TResult
将解析为
Task
。换句话说,您可以创建嵌套的
任务
实例:

var taskTask = new Task<Task>(async () =>
{
    await Task.Delay(-1);
});
var taskTask=新任务(异步()=>
{
等待任务。延迟(-1);
});
这样,您将有一个冷的外部任务,启动时将创建内部任务。创建任务所需的工作量可以忽略不计,因此将立即创建内部任务。与异步方法生成的所有任务一样,内部任务将是承诺式任务。承诺式任务在创建时总是很热门。它不能像基于委托的任务那样在冷状态下创建。调用其
Start
方法会导致
InvalidOperationException


创建冷任务和嵌套任务是一种在实践中很少使用的高级技术。按需启动承诺式任务的常用技术是将它们作为异步委托(各种风格的
Func
实例)传递,并在适当的时候调用每个委托。

类没有接受异步委托的类,因此传递给它的异步委托是无效的。这是一个常见的陷阱。仅仅因为编译器允许我们向任何lambda添加
async
关键字,并不意味着我们应该这样做。我们应该只将异步lambda传递给期望并理解它们的方法,这意味着参数的类型应该是带有
Task
返回值的。例如
Func
,或
Func
,或
Func

您可以做的是将异步lambda传递给
Task
构造函数,在这种情况下
TResult
将解析为
Task
。换句话说,您可以创建嵌套的
任务
实例:

var taskTask = new Task<Task>(async () =>
{
    await Task.Delay(-1);
});
var taskTask=新任务(异步()=>
{
等待任务。延迟(-1);
});
这样,您将有一个冷的外部任务,启动时将创建内部任务。创建任务所需的工作量可以忽略不计,因此将立即创建内部任务。与异步方法生成的所有任务一样,内部任务将是承诺式任务。承诺式任务在创建时总是很热门。它不能像基于委托的任务那样在冷状态下创建。调用其
Start
方法会导致
InvalidOperationException


创建冷任务和嵌套任务是一种在实践中很少使用的高级技术。按需启动承诺式任务的常用技术是将它们作为异步委托传递(各种风格的
Func
实例),并在适当的时候调用每个委托。

有趣的是,您有一个名为
操作的
列表。
您确定它不应该是
列表吗(或者它的异步等价物,
List
)?我不知道你是从哪里得到这段代码的。当然这看起来不像是一个例子。也许这是有用的。如果你更改
tasks.Add(task);
tasks.Add(task.Delay(-1));
@Andy不,那将不起作用。添加task.Delay(-1)您将得到一个invalidOperationException。@M1sterPl0w--为什么?它只是一个任务列表。有趣的是,您有一个名为
操作的
列表。
您确定它不应该是
列表(或其异步等价物
列表
)?我不知道您是从哪里获得此代码的。当然,这看起来不像一个示例。也许这是有用的。如果您更改
任务。添加(任务);
任务。添加(任务。延迟(-1));
@Andy不,这将不起作用。添加任务。延迟(-1)您将得到一个invalidOperationException。@M1sterPl0w--为什么?这只是一个任务列表。@user2555515区别在于您对它做了什么,而不是如何创建它,它没有显示,而且这不是一个好主意(因此我假设它没有显示)。副本显示了最后一段中描述的方法的实现。谢谢,但我失败了