【问题标题】:Task deadlocks because of Result由于 Result 导致的任务死锁
【发布时间】:2014-06-15 19:04:43
【问题描述】:

我有以下构造:一个异步执行一些加载任务的基类和一个仅将基类的结果转换为特殊数据类型的继承类(它只是一个带有一些扩展的通用版本,但这些都不重要)。

我最初调用继承类的Process-method:

    public TOut Process(object parameters)
    {
        return (TOut) StartProcessor(parameters).Result;
    }

该方法调用基类的以下方法:

    protected async Task<object> StartProcessor(object parameters)
    {
        if (State == PipelineState.Running) return null;
        if (!ValidatePipeline())
        {
            Logging.Error(
                "Pipeline can't start processor: There are some broken segment chain-links. Check your segment settings.");
            return null;
        }

        State = PipelineState.Running;
        _stopwatch.Start();

        object result = await Task.Run(() => RunPipeline(parameters));

        _stopwatch.Stop();

        if (result is PipelineState)
            State = (PipelineState) result;
        State = result != null ? PipelineState.Finished : PipelineState.Failed;

        RecentProcessTime = _stopwatch.Elapsed;
        _stopwatch.Reset();
        Logging.Debug("Finished process for pipeline {0} in: {1} ms.", Identifier,
            RecentProcessTime.TotalMilliseconds);

        return result;
    }

    private object RunPipeline(object parameter)
    {
        object recentResult = null;
        for (int i = 0; i < SegmentCount; i++)
        {
            if (_cancelProcess) // Cancel process
                return PipelineState.Cancelled;

            PipelineSegmentBase seg = Segments[i];
            if (i == 0) // If first, do initial process
            {
                recentResult = seg.Process(parameter, ProcessingDirection);
                continue;
            }
            if (i > 0 && recentResult == null) // If not first and recent result was null, process failed
                return PipelineState.Failed;

            seg.Process(recentResult, ProcessingDirection); // Process
        }

        return recentResult ?? PipelineState.Failed;
    }

现在,当然,继承类的 Process 方法由于 Result 属性而死锁。但是我怎么能避免这种情况呢?我看到了很多非常适合 void-methods 的文章。但是我得到了一些我必须返回到调用类的东西。我必须在流程方法中返回任务吗?我该怎么做才能让它异步运行,同时它最后仍然返回对象?

我真的不明白...使用 void-methods 很简单,但是由于我需要获取此任务的结果,所以它会死锁。我不明白这应该如何工作:-/

编辑:这很明显......

    public override object Process(object input, PipelineDirection direction)
    {
        if (!IsValidInput(input)) return null;
        Stream str = (Stream) input;
        // DEADLOCK
        return Core.IDE.GetGUICore().GetUIDispatcher().Invoke(() =>
        {
            Image i = new Image();
            i.BeginInit();
            i.Source = BitmapFrame.Create(str);
            i.EndInit();
            return i;
        });
    }

谢谢

【问题讨论】:

    标签: c# multithreading task-parallel-library deadlock multitasking


    【解决方案1】:

    我必须在 Process 方法中返回一个任务吗?

    这是最好的解决方案,是的:

    public Task<TOut> ProcessAsync(object parameters)
    {
        return StartProcessorAsync(parameters);
    }
    

    我该怎么做才能让它异步运行,而它最后仍然返回对象?

    这两种说法放在一起没有意义。想想看。您希望它异步运行,但同步返回结果。

    最好的解决方案是让代码异步。如果StartProcessorAsync 是异步的,那么调用它的所有东西也应该是异步的。这是编写异步代码的自然方式。

    有多种 hack 可以尝试让 synchronous over asynchronous 工作,但它们都不能在所有情况下工作 - 因为在某种程度上,这些 hack 中的每一个都必须尝试强制异步工作同步完成。那只是不能干净地工作。最好的解决方案是让异步工作异步。

    【讨论】:

    • 好的,有道理。但是当我现在想加载一些巨大的东西时,可能会以一种复杂的方式处理数据。假设这个过程大约需要 20 秒才能完成。我不想在这段时间内冻结我的 UI 线程。让程序执行此过程的最佳实践是什么,而我最后仍然有处理过的数据?不知何故,这必须起作用,否则将 TPL 用于实际返回某些内容的任务将毫无意义。还是我错了?
    • 如果你的 UI 线程使用await,那么它不会被冻结。 await 允许该方法异步等待结果。您可以使用 Task.Run 执行 CPU 绑定代码并使用 await 执行结果,或者如果您的需求更复杂,您可以使用 TPL Dataflow。
    • 好的,谢谢,这对我来说并不是什么新鲜事。但是要使用 await,您需要将方法声明为异步。如果我将调用方法声明为异步,则它必须返回一个任务。然后我必须再次调用“结果”,然后我不会再次陷入僵局吗?不都是一样的问题吗?
    • 它必须是“一直异步”。在 UI 应用程序中,这可能意味着您最终会使用异步事件处理程序。这样做的原因是因为async/await 的工作方式:他们不使用DoEvents 或任何类似的邪恶;相反,它们会返回,然后再继续。
    • 它死锁是因为Invoke正在等待UI线程,而UI线程被阻塞等待任务完成。它与this deadlock situation I describe on my blog 相似但不完全相同。您可以使用事件实现异步代码,但asyncawait 更简洁且更易于使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    • 1970-01-01
    • 2018-04-20
    • 2012-09-20
    • 2018-06-04
    相关资源
    最近更新 更多