2

私が実装しようとしているもの:

タスクをキューに入れ、指定された量を並行して実行するタスク スケジューラ。他のタスクは開始するまでキューで待機します。各タスクには、タスクの実行時にカウントを開始するタイムアウトがあり、その時間を超えると、タスクはキャンセルされ、ContinueWith (または直後に実行されるタスク) で処理される TimeoutException がスローされます。タスクはユーザーがキャンセルできる必要があります。

私が得るもの:

最初のタスクが失敗すると、他のすべてのタスクが即座に失敗します。

これが私のタスクスケジューラの完全なコードです(MSDNからいくつかの変更を加えて取得しました):

http://pastebin.com/KSMbDTH5。(問題の関数は 161 行にあります)

使用例は次のとおりです。

var taskTokens = new List<CancellationToken>();
var factory = new TaskScheduleFactory(new ParallelOptions() { MaxDegreeOfParallelism = 1 }); //for the purpose of testing, supposed to work and with higher values
for (var i = 0; i < 10; i++)
{
    //TaskScheduleFactory.cs, line 161
    var taskToken = factory.Add(
        (token) => //Task
        {
            Console.WriteLine("Start");
            Thread.Sleep(5000);
            if (token.IsCancellationRequested) return; //Cancelled by timeout
            Console.WriteLine("This should not print");
        },
        (task) => //ContinueWith
        {
            if (task.IsFaulted)
            {
                Console.WriteLine("Fail");
            }
            else if (!task.IsCompleted)
            {
                Console.WriteLine("Not completed");
            }
            else Console.WriteLine("Done");
        },
        2000 //Timeout
    );
    taskTokens.Add(taskToken);
}

どのように動作するか: (どちらのタスクも完了しないように、2 秒後にタイムアウト イベントを強制します)

MaxDegreeOfParallelism = 1 の場合:

Start;
(Wait 2sec)
Fail;
Start;
(Wait 2sec)
Fail;
....

MaxDegreeOfParallelism = 2 の場合:

Start;
Start;
(Wait 2sec)
Fail;
Fail;
Start;
Start;
(Wait 2sec)
Fail;
Fail;
....

仕組み:

Start;
(Wait 2sec)
Fail;
Fail;
Fail;
Fail;
...

(MaxDegreeOfParallelism = 1 の場合、残りもめちゃくちゃです)

注: これらは TPL での私の最初のステップです。

4

2 に答える 2

2

Addあなたの電話で.TimeoutAfter(timeoutInMilliseconds, cts)。これは、タスクを作成するとすぐにタイムアウトが開始されることを意味します。あなたの意図は、タスクの実行が開始されたときにのみタイムアウトを開始することだったと思います。

最初のタスクはタイムアウトよりも時間がかかるため、他のすべてのタスクは、順番が来たときにすでにタイムアウトになっています。

于 2016-03-02T13:05:05.403 に答える
1

完璧な解決策ではありませんが、私が考えることができる最善の解決策は次のとおりです。

public CancellationTokenSource Add(Action<CancellationToken> action, Action<Task> callback, int timeoutInMilliseconds)
{
    var cts = new CancellationTokenSource();
    Instance.StartNew(() =>
    {
        cts.CancelAfter(timeoutInMilliseconds);
        var task = Task.Factory.StartNew(() => action(cts.Token), cts.Token, TaskCreationOptions.AttachedToParent|TaskCreationOptions.LongRunning, TaskScheduler.Default);
        try
        {
            task.Wait(timeoutInMilliseconds, cts.Token);
        }
        catch (OperationCanceledException) { }
        callback(task);
    }, cts.Token);
    return cts;
}

要するに、タスクがキューから開始されると、デフォルトのタスクスケジューラに子タスクが作成され(他のタスクスケジューラがキューに入れるため)、一定の時間待機してコールバック関数を呼び出します。これがどれほど悪いかわかりません。

于 2016-03-07T07:52:37.087 に答える