Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 任务在等待时标记为RANTO完成,但仍在运行_C#_Asynchronous_Async Await - Fatal编程技术网

C# 任务在等待时标记为RANTO完成,但仍在运行

C# 任务在等待时标记为RANTO完成,但仍在运行,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我仍然在学习异步和多线程技术。我试图监视我启动的任务何时仍在运行(显示在UI中)。但是,它指示它比我想要的更早完成,当它等待时,甚至当我认为它的状态仍然在运行时。 这是我正在做的样品。这一切似乎都围绕着等待。当它点击等待时,它被标记为RANTO完成 我想跟踪开始这一切的主要任务,以某种方式向我表明,它仍然一直运行到最后,并且只有在完成所有任务后才能完成,包括回购调用和WhenAll 如何更改此项以获得有关TSKProdseeting任务状态的反馈 我的Console应用程序Main方法调用以下内

我仍然在学习异步和多线程技术。我试图监视我启动的任务何时仍在运行(显示在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);

异步函数一直同步运行,直到第一个
等待
,但在您可以