** 我在底部总结了这个问题,并进行了编辑**
以前有人问过这个问题,但我认为我的情况不同。
我正在同时处理多个请求。
这是我的代码,它在循环中运行。为了简洁起见,我删除了一些处理 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
完成之前不会完成。
所以你的代码很好。