等待已经运行的任务

阿洛瓦

我的应用程序具有类似全球资源的概念。解决方案中的每个部分都需要包含一些对象集合。其中一些在启动时加载,其他在首次访问时加载。

我的问题是第二种情况(延迟加载的集合)。在下面,您可以看到一个测试项目:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Wellcome!");

        var globalResources = new GlobalResources();

        var toolClassA = new MyToolClass(globalResources);
        var toolClassB = new MyToolClass(globalResources);

        // This two "Init" calls can not be awaited in real project.
        // They could be invoked by two different buttons
        _ = toolClassA.InitAsync();
        _ = toolClassB.InitAsync();

        Console.WriteLine("Finish");
        Console.ReadLine();
    }
}

public class MyToolClass
{
    private readonly GlobalResources _globalResources;

    public MyToolClass(GlobalResources globalResources)
    {
        _globalResources = globalResources ?? throw new ArgumentNullException(
            nameof(globalResources));
    }

    public async Task InitAsync()
    {
        await _globalResources.LoadAsync();
        Console.WriteLine("awaited");
    }
}

public class GlobalResources
{
    public bool _isLoaded;
    public readonly object _loadLock = new object();

    private string _externalQueryResult;

    private Task _runningLoadTask;

    public async Task LoadAsync()
    {
        if (_isLoaded)
        {
            return;
        }

        lock (_loadLock)
        {
            if (_isLoaded)
            {
                return;
            }
        }

        // A: Current code:
        {
            _externalQueryResult = await LongRunningQuery();
        }

        // B: Wanting something like this:
        {
            // If no task is already running then start one.
            if (_runningLoadTask == null)
            {
                _runningLoadTask = LongRunningQuery();
                await _runningLoadTask.Start(); // How await it?
            }
            // If a task ist already running then no db call should happen.
            // Instead the currently running task should be awaited.
            else
            {
                await Task.WaitAll(_runningLoadTask); // ???
                return;
            }
        }

        lock (_loadLock)
        {
            _isLoaded = true;
        }
    }

    public async Task<string> LongRunningQuery()
    {
        // This method should only be called once.
        Console.WriteLine("Loading data from Database (
            this line should only be written once on console window).");

        await Task.Delay(5000);
        return "123";
    }
}

我的问题是在课堂GlobalResources方法LoadAsync在这里您可以找到注释“ A ”,它表示我当前的编码方式。那是个问题,因为如果第二个加载请求发生,那么我将有两个数据库调用。

您可以在“ B部分找到我的解决方案我想将第一个请求的第一个任务存储在一个字段中。如果第二次调用进来,它应该等待存储的任务,以防止第二次调用数据库。

我的问题是我不知道如何编码。我认为如果手动使用“任务”,异步等待模式将无法正常工作。或您有任何想法吗?


在下面,您可以找到关键部分作为编译部分。(请注意damien-the-unbeliever的评论。发布的解决方案不是线程安全的!缺少一些锁)。

// B: Wanting something like this:
{
    // If no task is already running then start one.
    if (_runningLoadTask == null)
    {
        _runningLoadTask = LongRunningQuery();
        await _runningLoadTask; 
    }
    // If a task ist already running then no db call should happen.
    // Instead the currently running task should be awaited.
    else
    {
        await _runningLoadTask; 
        // Alternative way:
        // await Task.WhenAll(_runningLoadTask); 
    }
}
塞雷娅·波哥鲁波夫

首先,多次await 执行同一任务是可以的,并且不会损害您的数据库。因此,至少,您可以缓存此类任务(无论如何都可以锁定,这样很安全),以后再使用它即可。这样可以最大程度地减少锁定时间。

其次,由于您的资源在定义上是全局的,因此预先计算长时间运行的查询似乎是合理的。这意味着您可以在构造函数中运行适当的任务(不执行该任务await),而无需锁定,根本不需要锁定。

public MyConstructor()
{
    _myCachedTask = LongRunningTask(); // don't await it; hopefully, task is now running somewhere on the thread pool
}

...

public Task LongRunningTask() => _myCachedTask; // it's OK to await it multiple times, thread safe as well

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如果我等待已经运行或运行的任务会怎样?

取消已经运行的任务

立即运行任务,然后等待

多个任务。运行未正确等待/运行

等待新Task <T>(...):任务不运行?

运行任务,执行某些操作,然后等待?

是异步/等待允许其他任务运行

如何等待运行异步方法的任务

如何以不等待任务的预定速率运行任务?

了解异步已经运行了永远循环和挂起的任务

如何使用 pywinauto 使窗口(已经运行的任务)可见?

我的延续任务在完成运行之前似乎已经完成

等待一系列任务按顺序运行

make:并行运行多个任务,然后等待完成

更改长时间运行的等待任务的参数

运行多个异步任务并等待它们全部完成

EntityFramework在长时间运行的任务上,等待操作超时

如何在不等待的情况下运行Asyncio任务?

discord bot python 在等待用户响应时运行任务?

在 C# 中从已经运行的任务中初始化新任务

如何在用Beat再次运行celery任务之前检查其是否已经运行?

如何计划一个任务在bash中另一个已经运行的任务之后运行?

Celery - 一个任务运行 N 个任务,等待它们并处理结果

asyncio:仅在所有其他任务正在等待时才运行任务

当我不总是运行某些任务时该如何等待所有任务?

等待主机A上的任务完成,然后在单个剧本上在主机B上运行任务

如果事件循环已经在运行,如何在方法中等待协程同步完成?

等待任务永远取消等待

等待任务和等待任务之间的区别