【问题标题】:Is there a way to await a flag change in a function?有没有办法等待函数中的标志更改?
【发布时间】:2020-01-25 23:20:26
【问题描述】:

我尝试为我正在运行的算法创建一个简单的步进模式,如下所示:

    public async Task<bool> AStarAlgorithmAsync(PFSquare curr = null)
    {
        // some algorithm code here
        foreach(var square in Sorroundings)
        {
            if (SteppedMode)
            {
                await Task.Run(Pause);
            }
            if (await AStarAlgorithmAsync(square))
            {
                return true;
            }
        }
    }

在我的应用程序中,我有一个名为 SteppedMode 的布尔值,它决定算法是否应在每次点击事件时运行一次迭代。

Pause() 看起来像这样:

    private void Pause()
    {
        while (!ContinueStep) { }
        ContinueStep = false;
        return;
    }

在我的 (GUI) 应用程序的另一部分中,我有一个事件将布尔值 ContinueStep 设置为 true,理论上应该结束 while 循环并继续算法函数。目前这段代码锁定了我的 GUI 线程,我几乎可以肯定有更好的方法来做到这一点。

我试图让我的算法函数运行一次迭代,等待用户点击,然后才继续运行算法。有没有更简单、更清洁的方法来做到这一点?

(这是一个 GUI 应用程序,而不是控制台应用程序。)

【问题讨论】:

  • 不要将SteppedMode boolean 放在你的算法中,不如将步进模式算法编写为一个单独的函数呢?那么自动算法将简单地一遍又一遍地调用这个阶梯函数直到结束。
  • 我不明白为什么您发布的代码会从字面上锁定 GUI 线程。它会消耗大部分 CPU 时间,这会大大减慢速度。但不能完全锁定。也就是说,您可以使用TaskCompletionSource&lt;T&gt;,而不是等待轮询方法返回。请参阅标记的重复项。
  • @PeterDuniho 这个问题并不是真正的重复。我认为 OP 陷入了困境并试图解决错误的问题
  • @M.kazemAkhgary 好主意,我想我会试试的。
  • @PeterDuniho “问题通常需要先关闭,然后再改进。” 但不适合重复关闭(对于“需要重点”关闭,我完全同意)。假设知道(现有的)解决方案然后对(据称)改变为完全不同的问题持开放态度是没有意义的。这实际上违反了 SO 社区标准,因为此类更改需要作为一个完全独立的问题发布。

标签: c# asynchronous


【解决方案1】:

您的财产是兼职作为一种方法。

设置一个属性,然后让该属性立即恢复到其原始状态是没有意义的。作为消费者,我会对这种行为感到非常困惑。想想这段代码:

var myObj = new MyObject();

myObj.MyBoolean = true;

Console.WriteLine(myObj.MyBoolean); // FALSE!?

这只是没有意义。

您希望通过设置此属性触发的唯一效果是执行一些代码。这正是应该使用的方法:

public void ContinueStep()
{
    Console.WriteLine("I did some work");
}

所以不要这样:

myObj.ContinueStep = true;

你应该这样做:

myObject.ContinueStep();

这不会锁定您的 UI 线程,同时对您的消费者也更加敏感。该方法建议将采取一些行动(这可能会或可能不会导致对象中的状态更改 - 这是上下文期望)。


无限递归

顺便说一句;根据您的代码,AStarAlgorithmAsync 是一个递归函数,而且似乎无限。似乎没有结束条件。
每个递归关卡都会在第一个环境上进行交互,然后触发下一个关卡,下一个关卡将再次在第一个环境上进行交互,然后触发下一个关卡,这又是...

这不对,但我不清楚如何解决它,因为您的问题没有解释大局


一个简单的实现

我想要做的是让我的算法函数运行一次迭代,等待用户点击,然后才继续运行算法,有没有更简单、更干净的方法来做到这一点?

一个简单的例子:

private int _index = 0;

private List<object> _myList = ...; // assume this list contains some elements

public void ProcessNextObject()
{
    if(_index < _myList.Length)
    {
        Process(_myList[_index]);
        _index++;
    }
}

private void Process(object o)
{
    Console.WriteLine("Processing this object!");
}

然后您可以连接您的点击事件来调用ProcessNextObject()

请注意,在此示例中,列表被处理一次,不能再次处理。通过操纵索引值,您可以随意更改该行为。

【讨论】:

  • 它不是无限递归的,该函数还有更多代码,只是它会增加阅读的复杂性。另外,什么会进入我的 ContinueStep 函数?我的方法没有分步,我是否应该创建一个分步方法并每次都调用它?
  • “设置属性没有意义...” - 什么“属性”"...然后让该属性恢复到其原始状态" - 也许,但这正是 Windows 内核函数 SetEventauto-reset 事件所做的事情我>
  • 关于 myObject.ContinueStep(); 周围的更改 - 原始代码已经在名为 Pause() 的方法中,因此我们作为读者无需创建其他方法即可知道其意图。另外,方法是private,所以不会对调用者造成太大影响
  • 是的,也许,完全有可能。顺便说一句,上面这个问题的链接副本提到了.NET的MonitorAutoResetEvents(又是那个词)。两者都表现出相似的行为。
  • 这个地址如何“有没有办法await函数中的标志更改?”。您的答案与链接的重复项绝不相似,这一事实引起了人们的注意
猜你喜欢
  • 2021-01-25
  • 1970-01-01
  • 2019-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多