用连续来链接任务数组

时间:2012-06-30 18:30:31

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

我有一个有点复杂的任务结构(至少对我来说)。结构是:

(其中T =任务)

T1,T2,T3 ...... Tn。有一个数组(文件列表),T表示为每个文件创建的任务。 每个T总是有两个必须完成或失败的子任务:Tn.1,Tn.2 - 下载并安装。 对于每次下载(Tn.1),总有两个子任务要尝试,从两个路径下载(Tn.1.1,Tn.1.2)。

执行将是:

首先,下载文件:Tn1.1。如果Tn.1.1失败,则执行Tn.1.2。 如果下载任务中的任何一个返回OK - 执行Tn.2。 如果Tn.2执行或失败 - 转到下一个Tn。

我认为要做的第一件事就是用锯齿状数组编写所有这个结构:

    private void CreateTasks()
    {     
        //main array
        Task<int>[][][] mainTask = new Task<int>[_queuedApps.Count][][];
        for (int i = 0; i < mainTask.Length; i++)
        {
            Task<int>[][] arr = GenerateOperationTasks();
            mainTask[i] = arr;
        }
    }

    private Task<int>[][] GenerateOperationTasks()
    {
        //two download tasks 
        Task<int>[] downloadTasks = new Task<int>[2];
        downloadTasks[0] = new Task<int>(() => { return 0; });
        downloadTasks[1] = new Task<int>(() => { return 0; });

        //one installation task 
        Task<int>[] installTask = new Task<int>[1] { new Task<int>(() => { return 0; }) };

        //operations Task is jagged - keeps tasks above
        Task<int>[][] operationTasks = new Task<int>[2][];
        operationTasks[0] = downloadTasks;
        operationTasks[1] = installTask;

        return operationTasks;
    }

所以现在我得到了mainTask任务数组,包含了如上所述的精心排序的任务。但是在阅读了ContinuationTasks上的文档之后,我意识到这对我没有帮助,因为我必须打电话给Task.ContinueWith(任务2)。我很难在mainTask数组上执行此操作。我不能写mainTask [0] .ContinueWith(mainTask [1]),因为我不知道数组的大小。

如果我能以某种方式引用数组中的下一个任务(但不知道它的索引),但无法弄清楚如何。 有任何想法吗?非常感谢您的帮助。

此致

2 个答案:

答案 0 :(得分:1)

如何在排队的应用列表中使用并行库来安装?

正如svick在上面的评论中所说,尝试下载然后安装的过程是非常同步的,所以你不需要那些任务,只需要一些顺序代码。

但是对于下载所有应用程序并同时并行安装,您可能希望用您的数据填写应用程序列表并下载+安装方法,然后只需使用并行库来并行执行所有应用程序。这是一个例子,我从你的帖子中猜到了很多东西,但应该让你知道我在说什么。

如果你希望在一个单独的任务中完成整个任务并在所有应用程序并行下载时执行其他操作,则可以将并行代码包含在任务中并在代码中的其他位置执行,继续执行其他操作然后终于等待任务完成。

这可能是您要下载的每个应用的类:

/// <summary>
/// Class for each of your apps to be downloaded and installed. You can also
/// derive this in other types of apps that require a different download or install
/// approach.
/// </summary>
class AppToDownload
{
    /// <summary>
    /// The addresses to download this app
    /// </summary>
    public List<string> DownloadAddresses { get; set; }

    /// <summary>
    /// Flag that tells if this task was successfully installed. Set to false
    /// as default.
    /// </summary>
    public bool Installed { get; set; }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="downloadAddresses">Addresses to download this app from, they
    /// should be in order of preference</param>
    public AppToDownload(List<string> downloadAddresses)
    {
        this.DownloadAddresses = downloadAddresses;
        this.Installed = false;
    }

    /// <summary>
    /// Public method to be called to Install this app. It will download, and if
    /// successful, will install
    /// </summary>
    /// <returns></returns>
    public bool InstallApp()
    {
        this.Installed = (this.TryDownload() && this.TryInstall());
        return this.Installed;
    }

    /// <summary>
    /// Internal method to download this App. You can override this in a derived
    /// class if you need to.
    /// </summary>
    /// <returns></returns>
    protected virtual bool TryDownload()
    {
        bool res = false;

        // (...) Your code to download, return true if successful

        return res;
    }

    /// <summary>
    /// Internal method to install this App. You can override this in a derived
    /// class if you need to.
    /// </summary>
    /// <returns></returns>
    protected virtual bool TryInstall()
    {
        bool res = false;

        // (...) Your code to install, return true if successful

        return res;
    }
}

然后,下面是将并行下载和安装所有应用程序的代码。您还可以使用ParallelOptions类的实例来个性化Parallel循环的工作方式。

List<AppToDownload> queuedApps = new List<AppToDownload>();

// (...) Fill the list of apps

// Try Install all Apps in parallel
Parallel.ForEach(queuedApps, (app) => app.InstallApp());

答案 1 :(得分:1)

如果你想在后台线程上按顺序运行一些操作,你不需要很多Task,你只需要一个:

Task.Factory.StartNew(DownloadAndInstallFiles)

Task内,您可以使用常规顺序控制流结构,如foreachif来执行您想要的操作。类似的东西:

void DownloadAndInstallFiles()
{
    foreach (var file in files)
    {
       var downloaded = Download(file, primarySource);
       if (downloaded == null)
           downloaded = Download(file, secondarySource);

       if (downloaded != null)
           Install(downloaded);
    }
}