C# 任务在等待时标记为RANTO完成,但仍在运行
我仍然在学习异步和多线程技术。我试图监视我启动的任务何时仍在运行(显示在UI中)。但是,它指示它比我想要的更早完成,当它等待时,甚至当我认为它的状态仍然在运行时。 这是我正在做的样品。这一切似乎都围绕着等待。当它点击等待时,它被标记为RANTO完成 我想跟踪开始这一切的主要任务,以某种方式向我表明,它仍然一直运行到最后,并且只有在完成所有任务后才能完成,包括回购调用和WhenAll 如何更改此项以获得有关TSKProdseeting任务状态的反馈 我的Console应用程序Main方法调用以下内容:C# 任务在等待时标记为RANTO完成,但仍在运行,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我仍然在学习异步和多线程技术。我试图监视我启动的任务何时仍在运行(显示在UI中)。但是,它指示它比我想要的更早完成,当它等待时,甚至当我认为它的状态仍然在运行时。 这是我正在做的样品。这一切似乎都围绕着等待。当它点击等待时,它被标记为RANTO完成 我想跟踪开始这一切的主要任务,以某种方式向我表明,它仍然一直运行到最后,并且只有在完成所有任务后才能完成,包括回购调用和WhenAll 如何更改此项以获得有关TSKProdseeting任务状态的反馈 我的Console应用程序Main方法调用以下内
Task tskProdSeeding;
tskProdSeeding = Task.Factory.StartNew(SeedingProd, _cts.Token);
运行以下命令的:
private async void SeedingProd(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
await Task.WhenAll(Task.Run(async () =>
{
foreach (var code in codesToSeed)
{
if (!token.IsCancellationRequested)
{
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
}
}, token));
Thread.Sleep(30000);
}
}
如果使用
async void
外部任务无法判断任务何时完成,则需要改用async task
其次,一旦切换到异步任务
,任务.Factory.StartNew
无法处理返回任务
的函数,则需要切换到任务.Run(
完成这两项更改后,您将能够等待或在tskprodseeting
上执行.Wait()
,它将正确地等待,直到所有工作完成后再继续
请阅读“”以了解有关不执行async void
的更多信息
请阅读“”,了解您不应以新的方式使用Start的更多原因
注意:在
SeedingProd
中,您应该将其切换为使用等待任务。延迟(30000);
插入线程。睡眠(30000);
,这样您就不会在线程等待时捆绑线程。如果您这样做,您可能会丢弃线程
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
就这么办吧
tskProdSeeding = SeedingProd(_cts.Token);
因为函数内部不再有阻塞调用。如果使用
async void
外部任务无法判断任务何时完成,则需要改用async task
其次,一旦切换到异步任务
,任务.Factory.StartNew
无法处理返回任务
的函数,则需要切换到任务.Run(
完成这两项更改后,您将能够等待或在tskprodseeting
上执行.Wait()
,它将正确地等待,直到所有工作完成后再继续
请阅读“”以了解有关不执行async void
的更多信息
请阅读“”,了解您不应以新的方式使用Start的更多原因
注意:在
SeedingProd
中,您应该将其切换为使用等待任务。延迟(30000);
插入线程。睡眠(30000);
,这样您就不会在线程等待时捆绑线程。如果您这样做,您可能会丢弃线程
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
就这么办吧
tskProdSeeding = SeedingProd(_cts.Token);
因为函数内部不再有阻塞调用。当您在方法上指定
async
时,它会编译成带有任务的状态机,因此SeedingProd
不会同步运行,而是充当任务,即使返回void
。因此,当您调用Task.Factory.StartNew(SeedingProd)时
您启动的任务启动了另一个任务-这就是为什么第一个任务在第二个任务之前立即完成。您只需添加任务
返回参数,而不是无效
:
private async Task SeedingProdAsync(CancellationToken ct)
{
...
}
简单地说就是这样:
Task tskProdSeeding = SeedingProdAsync(_cts.Token);
当您在方法上指定
async
时,它会编译成一个带有任务的状态机,因此SeedingProd
不会同步运行,但即使返回void
,也会充当任务。因此,当您调用Task.Factory.StartNew(SeedingProd)时
您启动的任务启动了另一个任务-这就是为什么第一个任务在第二个任务之前立即完成。您只需添加任务
返回参数,而不是无效
:
private async Task SeedingProdAsync(CancellationToken ct)
{
...
}
简单地说就是这样:
Task tskProdSeeding = SeedingProdAsync(_cts.Token);
我不认为您需要第二个线程(
Task.Run
或StartNew
)一点也不。看起来大部分工作都是I/O绑定的,如果你是异步进行的,并且使用的是Task.Delay
而不是Thread.Sleep
,那么这些操作就会消耗掉你的UI,你的UI就不应该冻结。对于异步新手来说,首先需要了解的是,它与多线程不同。后者都是关于消耗更多的线程,前者是关于消耗更少的线程。专注于消除阻塞,你不应该需要第二个线程
正如其他人所指出的,SeedingProd
需要返回一个任务,而不是void
,因此您可以观察其完成情况。我相信您的方法可以简化为:
private async Task SeedingProd(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
foreach (var code in codesToSeed)
{
if (token.IsCancellationRequested)
return;
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
await Task.Dealy(30000);
}
}
然后简单地调用该方法,而不等待它,您就可以完成任务了
Task mainTask = SeedingProd(token);
我不认为您需要第二个线程(Task.Run
或StartNew
)一点也不。看起来大部分工作都是I/O绑定的,如果你是异步进行的,并且使用的是Task.Delay
而不是Thread.Sleep
,那么这些操作就会消耗掉你的UI,你的UI就不应该冻结。对于异步新手来说,首先需要了解的是,它与多线程不同。后者都是关于消耗更多的线程,前者是关于消耗更少的线程。专注于消除阻塞,你不应该需要第二个线程
正如其他人所指出的,SeedingProd
需要返回一个任务,而不是void
,因此您可以观察其完成情况。我相信您的方法可以简化为:
private async Task SeedingProd(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
foreach (var code in codesToSeed)
{
if (token.IsCancellationRequested)
return;
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
await Task.Dealy(30000);
}
}
然后简单地调用该方法,而不等待它,您就可以完成任务了
Task mainTask = SeedingProd(token);
异步函数一直同步运行,直到第一个等待
,但在您可以