1

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

(其中 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(Task2)。我很难在我的 mainTask 数组上这样做。我不能写 mainTask[0].ContinueWith(mainTask[1]) 因为我不知道数组的大小。

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

问候,

4

2 回答 2

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());
于 2012-06-30T20:55:17.367 回答
1

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

Task.Factory.StartNew(DownloadAndInstallFiles)

在里面Task,你可以使用正常的顺序控制流结构,比如foreachifs 来做你想做的事。就像是:

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

       if (downloaded != null)
           Install(downloaded);
    }
}
于 2012-06-30T21:13:34.473 回答