1

少し複雑なタスク構造があります(少なくとも私にとっては)。構造は次のとおりです。

(T = タスク)

T1、T2、T3... Tn。配列 (ファイルのリスト) があり、T は各ファイルに対して作成されたタスクを表します。各 T には、完了するか失敗する必要がある 2 つのサブタスクが常にあります: Tn.1、Tn.2 - ダウンロードとインストール。各ダウンロード (Tn.1) には、2 つのパス (Tn.1.1、Tn.1.2) からのダウンロードを試行する 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 配列を取得しました。ただし、ContinueTasks のドキュメントを読んだ後、たとえば Task.ContinueWith(Task2) を呼び出す必要があるため、これは役に立たないことに気付きました。mainTask 配列でこれを行うことに困惑しています。配列のサイズがわからないので、mainTask[0].ContinueWith(mainTask[1]) と書けません。

配列内の次のタスクを何らかの方法で参照できた場合 (ただし、そのインデックスを知らなくても)、その方法がわかりません。何か案は?ご助力ありがとうございます。

よろしく、

4

2 に答える 2

1

バックグラウンド スレッドでいくつかの操作を順番に実行したい場合、多くのTasks は必要ありません。必要なのは 1 つだけです。

Task.Factory.StartNew(DownloadAndInstallFiles)

そして、その内部では、やs などの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);
    }
}
于 2012-06-30T21:13:34.473 に答える
1

キューに入れられたアプリのリストで Parallel ライブラリを使用してインストールするのはどうですか?

上記のコメントで svick が述べているように、ダウンロードしてからインストールしようとするプロセスは非常に同期的であるため、そのためのタスクは必要なく、一連のコードだけが必要です。

ただし、すべてのアプリをダウンロードして同時にインストールするには、アプリのリストにデータとダウンロード + インストール メソッドを入力し、Parallel ライブラリを使用してすべてを並行して実行することができます。これが例です。あなたの投稿から多くのことを推測しましたが、私が話していることのアイデアを提供する必要があります.

全体を別のタスクに入れ、すべてのアプリを並行してダウンロードしている間に他のことをしたい場合は、並列コードをタスクに囲んでコードの別の場所で実行し、他のことを続けてから最後に待つことができますタスクを完了するために。

これは、ダウンロードする各アプリのクラスになる可能性があります。

/// <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 に答える