简体   繁体   English

异步操作中的依赖关系和执行顺序

[英]Dependency and Execution Order in Asynchronous Operations

I am working on an application which performs remote installation of various software components. 我正在开发执行各种软件组件的远程安装的应用程序。 There exist some component installation order dependencies across machines, and these component installs are all performed asynchronously. 跨机器存在一些组件安装顺序依赖性,并且这些组件安装都是异步执行的。

I'm wondering what the best approach is to establishing these component installation order dependencies. 我想知道什么是建立这些组件安装顺序依赖性的最佳方法。 For example, I have what I call "Target Machines" A and B, and Components 1 and 2. Here, installing Component 2 on Machine B must wait for the completion of Component 1 on Machine A. This is a very simple example, but I want to establish a framework so that more complex scenarios can be easily implemented. 例如,我有所谓的“目标机器” A和B,以及组件1和2。这里,在机器B上安装组件2必须等待机器A上组件1的完成。这是一个非常简单的示例,但是我想建立一个框架,以便可以轻松实现更复杂的方案。

My current logic is as follows: 我当前的逻辑如下:

foreach (var tm in TargetMachines)
{
    IProgress<InstallProgress> p = tm.Progress;

    // Get installer module for this target machine
    var installModule =
        ServiceLocator.Default.GetAllInstances<IInstallModule>()
            .FirstOrDefault(m => m.ProductFamily.Equals(GetCurrentProductFamily()));

    // Add the Install() task to the queue
    if (installModule != null)
        installationTasks.Add(installModule.Install(tm.MachineName, p));
}

Here, I'm simply iterating through each available installModule for each Target Machine and running its Install() method. 在这里,我只是为每个目标计算机遍历每个可用的installModule并运行其Install()方法。 My concrete InstallModule implementations are responsible for invoking the Component installation in a prescribed (currently hardcoded) order. 我的具体InstallModule实现负责按规定的顺序(当前为硬编码)调用Component安装。

You can think of two concurrent timelines: 您可以想到两个并发的时间表:

[Target Machine A] === Component 1 ===> Finished

[Target Machine B] === Component 2 [Wait on Target Machine A, Component 1] ===> Finished

As evidenced from this post's title, I saw a similar feature in Dynamics CRM's docs , but nothing the .NET BCL which looks appropriate. 从这篇文章的标题可以看出,我在Dynamics CRM的文档中看到了类似的功能,但是没有什么合适的.NET BCL。

I understand that I have the option to use ContinueWith , such that I can do taskA.ContinueWith(taskB) . 我了解我可以选择使用ContinueWith ,以便可以执行taskA.ContinueWith(taskB) However, I am primarily interested in how to represent these dependencies in such a way that I can construct the task chain from it. 但是,我主要对如何表示这些依赖项感兴趣,以便可以从中构造任务链。

I also found this article which implements a DependencyManager but predates the TPL. 我也发现这个文章它实现了一个DependencyManager但早于TPL。 Not sure if this is a best-practices solution five years hence. 不确定五年后这是否是最佳实践解决方案。

EDIT 1 : Potential solution here from Microsoft, the "Task Graph Pattern". 编辑1:潜在的解决方案在这里从微软的“任务图模式”。

EDIT 2 : Per svick's suggestion, I am experimenting with this: 编辑2 :根据svick的建议,我正在尝试以下方法:

public class Component
{
    public Component()
    {
        Dependencies = new List<Component>();
    }

    public IEnumerable<Component> Dependencies { get; set; }

    public Task<ExecutionResult> InstallationCompletion { get; set; }

    public async Task<ExecutionResult> InstallAsync()
    {
        // http://stackoverflow.com/questions/25385129/dependency-and-execution-order-in-asynchronous-operations

        await Task.WhenAll(Dependencies.Select(c => c.InstallationCompletion));

        // install this component here

        var executionResult = new ExecutionResult(0, "Installation completed");
        return executionResult;
    }
}

What I would do is to make each component contain a list of components that it depends on and also expose a Task indicating that installation of that component completed. 我要做的是使每个组件包含它所依赖的组件的列表,并公开一个Task指示该组件的安装已完成。

You can then do something like: 然后,您可以执行以下操作:

// there is no non-generic TaskCompletionSource, so use bool
private TaskCompletionSource<bool> installationCompletion
    = new TaskCompletionSource<bool>();

public Task InstallationCompletion { get { return installationCompletion.Task; } }

public async Task InstallAsync()
{
    await Task.WhenAll(this.Dependencies.Select(c => c.InstallationCompletion));

    // install this component here

    installationCompletion.SetResult(true);
}

(Possibly also using inheritance to keep the common code in one place only.) (可能还使用继承将通用代码仅保留在一个位置。)

Then you can start the installation of all components at the same time, the dependencies will take care of themselves thanks to the above code. 然后,您可以同时开始安装所有组件,由于上面的代码,依赖项将自行解决。

await Task.WhenAll(allComponents.Select(c => c.InstallAsync()));

If you can't use C# 5.0, you can use Task.Factory.ContinueWhenAll() for the same purpose as await Task.WhenAll() , only with worse syntax. 如果您不能使用C#5.0,则可以将Task.Factory.ContinueWhenAll()用于与await Task.WhenAll()相同的目的,但语法更差。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM