我正在开发一个执行远程安装各种软件组件的应用程序。跨机器存在一些组件安装顺序依赖关系,这些组件安装都是异步执行的。
我想知道建立这些组件安装顺序依赖项的最佳方法是什么。例如,我有我称之为"目标机器" A和B,以及组件1和2.这里,在机器B上安装组件2必须等待机器A上的组件1的完成。这是一个非常简单的示例,但我想建立一个框架,以便更复杂的方案可以很容易实现。
我目前的逻辑如下:
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));
}
在这里,我只是为每个目标计算机迭代每个可用的installModule
并运行其Install()
方法。我的具体InstallModule
实现负责以规定的(当前硬编码的)顺序调用Component安装。
您可以考虑两个并发时间轴:
[Target Machine A] === Component 1 ===> Finished
[Target Machine B] === Component 2 [Wait on Target Machine A, Component 1] ===> Finished
从这篇文章的标题中可以看出,我在Dynamics CRM的docs中看到了类似的功能,但看起来不合适的.NET BCL。
我知道我可以选择使用ContinueWith
,这样我就可以taskA.ContinueWith(taskB)
。但是,我主要关注如何表示这些依赖关系,以便我可以从中构建任务链。
我还发现this文章实现了DependencyManager
,但早于TPL。五年后不确定这是否是最佳实践解决方案。
编辑1 :来自Microsoft的潜在解决方案here,&#34;任务图模式&#34;。
编辑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;
}
}
答案 0 :(得分:3)
我要做的是让每个组件包含它所依赖的组件列表,并公开Task
,表明该组件的安装已完成。
然后您可以执行以下操作:
// 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);
}
(可能还使用继承将公共代码保留在一个地方。)
然后您可以同时开始安装所有组件,由于上面的代码,依赖关系将自行处理。
await Task.WhenAll(allComponents.Select(c => c.InstallAsync()));
如果您无法使用C#5.0,则可以将Task.Factory.ContinueWhenAll()
用于与await Task.WhenAll()
相同的目的,但语法较差。