我应该在我的 Task.Run() 中使用 await 吗?



** 我在底部总结了这个问题,并进行了编辑**

以前有人问过这个问题,但我认为我的情况不同。

我正在同时处理多个请求。

这是我的代码,它在循环中运行。为了简洁起见,我删除了一些处理 taskAssigned 变量的代码。

while (!taskAllocated)
{
lock (_lock)
{
// Find an empty slot in the task queue to insert this task
for (i = 0; i < MaxNumTasks; i++)
{
if (_taskQueue[i] == null)
{
_taskQueue[i] = Task.Run(() => Process());
_taskQueue[i].ContinueWith(ProcessCompleted);
break;
}
}
}
}

工艺是一种典型的async Task Process() { CpuIntensiveStuff(); }方法。

我一直在运行上面的代码,它一直工作正常。它很好地多线程。每当一个项目进来时,它都会在任务队列中找到一个空槽,然后把它踢掉。任务完成后,将运行 ProcessCompleted 方法,并释放槽。

但后来我想,我不应该在我的Task.Run里使用await吗?像这样:

_taskQueue[i] = Task.Run(async () => await Process());

想了想,我不确定。 当任务完成时,ContinueWith会正确触发,因此也许没有必要。

我问是因为我想监控和记录每个任务完成所需的时间。

所以代替 Process(),我会制作另一种方法,例如:

async Task DoProcess() 
{ 
var sw = Stopwatch.StartNew();
Process();
sw.Stop();
Log(sw.ElapsedMilliseconds);
}

我突然想到,如果我这样做,我不确定我是否需要await Process();,除了不知道我是否应该在Task.Run()内等待

我对此有点头晕目眩。 任何人都可以提供指导吗?


编辑:

总结一下:

如果某个方法是:

void SomeMethod() { }

然后

Task.Run(() => SomeMethod());很棒,在新的"线程"上调用 SomeMethod(不是技术上的,但你知道我的意思)。

但是,我SomeMethod实际上是:

async Task SomeMethod() { }

你需要对Task.Run()做任何特别的事情吗?

我的代码,我不是,我只是直接忽略它是一个异步任务,这似乎有效:

Task.Run(() => SomeMethod()); // SomeMethod is async Task but I am ignoring that

但我不相信它 a) 应该有效或 b) 是一个好主意。另一种方法是:

Task.Run(async() => await SomeMethod());

但是有什么意义吗?而这又因我真正想做的事情而变得更加复杂:

Task.Run(() => 
{ 
someCode(); 
var x = startTimer();
SomeMethod(); 
var y = stopTimer();
someMoreCode()
}); 

但是如果没有等待,我不确定它会等待某个方法完成并且计时器会出错。

如果你不使用匿名方法,事情会变得更加清晰。例如

Task.Run(() => Process())

相当于这个:

Task.Run(DoSomething);
Task DoSomething() {
return Process();
}

Task.Run(async () => await Process())

相当于这个:

Task.Run(DoSomething);
async Task DoSomething() {
await Process();
}

在大多数情况下,return SomethingThatReturnsATask()return await SomethingThatReturnsATask()之间没有功能差异,您通常希望直接返回Task而不使用await(出于此处描述的原因)。在Task.Run内部使用时,如果 .NET 团队没有您的支持,事情很容易变得糟糕。

请务必注意,异步方法开始在同一线程上运行,就像任何其他方法一样。魔术发生在作用于不完整Task的第一个await。此时,await返回自己的不完整Task。这很重要 - 它会返回,并承诺稍后再做其余的工作。

这可能意味着,每当Process()返回Task时,从Task.Run返回的Task就会完成。由于Process()在第一个await返回一个Task,所以当它还没有完全完成时就会发生这种情况。

.NET 团队支持您

但是,情况并非如此,因为当您为它提供返回Task的方法时,Task.Run具有特定的重载。如果您查看代码,它会返回一个与您返回Task相关联的Task*。

这意味着从Task.Run(() => Process())返回的Task在从Process()返回的Task完成之前不会完成。

所以你的代码很好。

最新更新