【问题标题】:Task unable to timeout任务无法超时
【发布时间】:2017-08-21 12:34:13
【问题描述】:

我使用 TPL 实现了一个简单的任务。它等待 10 秒执行并返回 true/false。

var checkCFOPTask = Task.Run(() => CheckCFOPExists());
checkCFOPTask.Wait(TimeSpan.FromSeconds(10));
if (checkCFOPTask.Result)
{

}
else
{

}

问题是我的代码卡在 if 语句中。

if (checkCFOPTask.Result)

每次我暂停调试器时,它仍然在上面的代码行中等待。这是第一次发生。理想情况下,它应该在 10 秒内返回真/假。

以下是函数定义-

CheckCFOExists:由任务执行。

private bool CheckCFOPExists()
{
    bool found = false;

    try
    {
        while (!found)
        {
            try
            {
                if (ieDriver.FindElement(By.Id("popup_message")).Text == "Não existem itens para realizar o rateio.")
                {
                    ResetInvoiceSearchScreen();
                    break;
                }
            }
            catch (Exception ex)
            {

            }

            try
            {
                if (arrCFOPList.Contains(ieDriver.FindElement(By.Id("vendorNF.cfopOperCode")).GetAttribute("value")))
                {
                    found = true;
                }
            }
            catch (Exception ex)
            {

            }
        }
    }
    catch (Exception ex)
    {

    }
    return found;
}

ResetInvoiceSearchScreen:在上述函数内执行

private void ResetInvoiceSearchScreen()
{
    try
    {
        ieDriver.FindElement(By.Id("popup_ok")).Click();
        ieDriver.FindElement(By.Id("ltmCnpjCpf")).Clear();
        ieDriver.FindElement(By.Id("notaFiscalNbr")).Clear();
        ieDriver.FindElement(By.Id("inbNotaFiscalId")).Clear();
        ieDriver.FindElement(By.Id("seriesFrmCd")).Clear();
    }
    catch (Exception ex)
    {

    }
}

是否还需要其他东西来确保函数正确超时?如果我可以提供更多详细信息,请告诉我。

编辑

我在 Visual Studio 的即时窗口中看到checkCFOPTask.Result 的以下消息-

Id = Cannot evaluate expression because the code of the current method is optimized., Status = Cannot evaluate expression because the code of the current method is optimized., Method = Cannot evaluate expression because the code of the current method is optimized., Result = Cannot evaluate expression because the code of the current method is optimized.

【问题讨论】:

  • 如果没有在 10 秒内完成,它应该如何返回 true 或 false?
  • 我认为您在寻找 Task.IsCompleted 而不是 Task.Result

标签: c# .net task-parallel-library


【解决方案1】:

在使用 Result 之前,您需要检查您的任务是否真的通过Task.IsCompleted 完成。

if (checkCFOPTask.IsCompleted && checkCFOPTask.Result)

【讨论】:

    【解决方案2】:

    您似乎需要为您正在调用的方法添加超时支持 - 因为如果它找不到它正在寻找的东西,它将永远循环。

    最简单的方法是将CancellationToken 传递给方法。您还应该将测试代码分解为返回 bool 的单独方法。

    还请注意,您有一个繁忙的循环,这在轮询时通常不是一个好主意!如果您要轮询的东西不可用,最好在轮询时引入一个小睡眠。 (注意:如果您有更好的检查方法,轮询通常不是一个好方法,但看起来您在这里没有其他可以使用的方法,因此必须进行轮询。)

    你可以这样写你的方法(我省略了轮询你正在寻找的东西的代码,以便专注于其他逻辑):

    private bool CheckCFOPExists(CancellationToken cancel)
    {
        TimeSpan retryDelay = TimeSpan.FromMilliseconds(500);
    
        while (true)
        {
            if (tryToFindTheThing()) // Blocking call.
                return true;
    
            if (cancel.WaitHandle.WaitOne(retryDelay))
                return false;
        }
    }
    
    bool tryToFindTheThing()
    {
        return false;  // Your implementation goes here.
    }
    

    然后调用它并有 10 秒的超时,你会做这样的事情(可编译的控制台应用程序):

    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ConsoleApp3
    {
        class Program
        {
            static void Main()
            {
                var test = new Program();
    
                // Create a cancellation token source that cancels itself after 10 seconds:
                var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(10));
    
                // Create and run the task:
    
                var sw = Stopwatch.StartNew();
                var checkCFOPTask = Task.Run(() => test.CheckCFOPExists(cancellation.Token));
    
                Console.WriteLine("Waiting for task to finish.");
                Console.WriteLine($"Task returned: {checkCFOPTask.Result} after {sw.ElapsedMilliseconds} ms");
            }
    
            private bool CheckCFOPExists(CancellationToken cancel)
            {
                TimeSpan retryDelay = TimeSpan.FromMilliseconds(500);
    
                while (true)
                {
                    if (tryToFindTheThing()) // Blocking call.
                        return true;
    
                    if (cancel.WaitHandle.WaitOne(retryDelay))
                        return false;
                }
            }
    
            bool tryToFindTheThing()
            {
                return false;  // Your implementation goes here.
            }
        }
    }
    

    【讨论】:

    • 感谢您的详细信息!我理解你的解释,但你能解释为什么即使被调用的方法进入一个永无止境的循环,任务也不会超时。是因为非托管资源调用(在我的情况下是 selenium IE 驱动程序)还是其他原因?
    • @SouvikGhosh 当您调用checkCFOPTask.Wait(TimeSpan.FromSeconds(10)) 时,它所做的只是等待最多10 秒以等待任务完成,然后如果任务在分配的时间内完成,则返回true,或者@987654326 @如果没有。它不会阻止任务执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2017-09-20
    • 1970-01-01
    • 2019-11-06
    • 2013-12-15
    相关资源
    最近更新 更多