-1

プロデューサーとコンシューマーの乗算タスク クラスがあります。私は方法を持っています:

  private async Task Consume(CancellationToken cancellationToken){..}

開始方法があります:

    public void Run()
    {
        var workerCount = Session.GetParameters().GetThreadCount();
        _workers = new List<Task>(workerCount);
        for (var i = 0; i < workerCount; i++)
            _workers.Add(Consume(StopCancellationTokenSource.Token));
        Task.WhenAll(_workers).ContinueWith(_ => DoneEvent);
    }

問題は、DoneEventが発生することですが、サブスクライバー イベント ハンドラーが実行されないことです。イベント ハンドラーの実行に成功した唯一の方法は、Run メソッドをasyncにして await beforeを追加したことTask.WhenAll(..)です。しかし、その後、別の問題が提起されました。メソッドConsume()にはManualResetEvent PauseBlock. また、リセットされると、メインスレッドも待機します。

事前にt​​hnx。

編集: 私はそれを正しく行うことができました(2日後)、Runメソッドを少し変更しました:

    public async void Run()
    {
        var workerCount = Session.GetParameters().GetThreadCount();
        _workers = new List<Task>(workerCount);
        for (var i = 0; i < workerCount; i++)
            _workers.Add(Task.Run(()=> Consume(StopCancellationTokenSource.Token)));
        await Task.WhenAll(_workers);
        DoneEvent();
    }

現在、正しく動作しています。参考までに消費者の方法:

    private async Task Consume(CancellationToken cancellationToken)
    {
        try
        {
            await Task.Delay(5000, cancellationToken);
            IEngGroup engGroup;
            while (Groups.TryDequeue(out engGroup))
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (!engGroup.IsEnabled || engGroup.Result.Status == ItemRunningStatus.Successful) continue;

                if (engGroup.IsBreak) Pause();
                //if paused wait
                PauseBlock.WaitOne();
                //if stoped throw
                cancellationToken.ThrowIfCancellationRequested();

                var groupRunner = new GroupRunner(cancellationToken, PauseBlock);

                if (engGroup.FireAndForget)
                    groupRunner.RunGroup(engGroup);
                else
                    await groupRunner.RunGroup(engGroup);
            }
            return;
        }
        catch (OperationCanceledException)
        {
            return ;
        }
    }

皆様にthnx. 改善すべき点について何か提案があれば、私はそれを見たいと思います。

4

1 に答える 1

0

これを試して:

Run().ConfigureAwait(false);

public async Task Run()
{
    ...
    await Task.WhenAll(_workers).ContinueWith(_ => DoneEvent);
}

したがって、これにより、現在のスレッドに再度戻る必要がなく、実行したスレッドで実行を終了する必要がないことが実行に通知されます。メインスレッドをブロックしません。

ただし、「DoneEvent」で実行されたコードは他のスレッドで実行されるため、UI スレッドなどに影響を与えるコードがある場合は、無効なクロススレッド アクセス例外が発生します。

于 2015-04-07T12:11:58.943 に答える