Информация об изменениях

Сообщение Re[3]: Почему не отменяется задача? от 15.03.2021 21:27

Изменено 15.03.2021 22:13 Mystic Artifact

Re[3]: Почему не отменяется задача?
Здравствуйте, Passerby, Вы писали:

P>Здравствуйте, Mystic Artifact, Вы писали:

MA>> Потому что в цикле i всегда равно нолю?
P>Спасибо, исправил. Писал While, а для форума решил исправить на for, ошибку не заметил.
P>Вопрос остается. Почему нет отмены?

1. async методы всегда выполняются синхронно в месте вызова, до точки разрыва (await). Т.е. в таком состоянии твой код просто исполняется синхронно, и отмена не происходит просто потому, что, там некому его отменять. Поставь Console.WriteLine(i) в цикле, что бы видеть кол-во происходящих итераций.

2. В SignalNoServer v.Wait(ct) — бросает исключение при отмене (не уверен, что это предполагалось).

3. task.Dispose(); — нельзя делать без проверки состояния задачи, иначе получишь опять исключение.

В примере ниже в цикле запускается целая пачка SignalNoServer потому, что в твоём изначальном примере так и предполагалось видимо.

        static async Task Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            Task task = null;
            for (int i = 0; ; i++)
            {
                Console.WriteLine(i);

                if (i != 0)
                {
                    cts.Cancel();
                    Thread.Sleep(10);
                    // task.Dispose();
                }

                cts = new();
                task = SignalNoServer(cts.Token);
            }
        }

        static async Task SignalNoServer(CancellationToken ct)
        {
            await Task.Yield(); // безусловный разрыв

            var v = Task.Delay(2000, ct);

            try
            {
                v.Wait(ct);
            }
            catch (OperationCanceledException ocex)
            {
            }

            if (!v.IsCanceled) Console.WriteLine("Обработка закончена " + DateTime.Now);
            else Console.WriteLine("Cancelled: " + DateTime.Now);
            //или другой вариант, в котором тоже нет отмены
            //if (!ct.IsCancellationRequested) Console.WriteLine("Обработка закончена " + DateTime.Now);
            v.Dispose();
        }


PS: Вместо таких городушек — можно было бы просто написать await.

        static async Task SignalNoServer(CancellationToken ct)
        {
            var v = Task.Delay(2000, ct);
            try
            {
                await v;
            }
            catch (OperationCanceledException) { }

            // if (ct.IsCancellationRequested) Console.WriteLine("Cancellation requested " + DateTime.Now);
            if (!v.IsCanceled) Console.WriteLine("Обработка закончена " + DateTime.Now);
            else Console.WriteLine("Cancelled: " + DateTime.Now);
            //или другой вариант, в котором тоже нет отмены
            //if (!ct.IsCancellationRequested) Console.WriteLine("Обработка закончена " + DateTime.Now);
            v.Dispose();
        }


PPS: Понятно, что мои исправления так же грязны как и исходный пример.
Re[3]: Почему не отменяется задача?
Здравствуйте, Passerby, Вы писали:

P>Здравствуйте, Mystic Artifact, Вы писали:

MA>> Потому что в цикле i всегда равно нолю?
P>Спасибо, исправил. Писал While, а для форума решил исправить на for, ошибку не заметил.
P>Вопрос остается. Почему нет отмены?

1. async методы всегда выполняются синхронно в месте вызова, до точки разрыва (await). Т.е. в таком состоянии твой код просто исполняется синхронно, и отмена не происходит просто потому, что, там некому его отменять. Поставь Console.WriteLine(i) в цикле, что бы видеть кол-во происходящих итераций.

2. В SignalNoServer v.Wait(ct) — бросает исключение при отмене (не уверен, что это предполагалось).

3. task.Dispose(); — нельзя делать без проверки состояния задачи, иначе получишь опять исключение.

В примере ниже в цикле запускается целая пачка SignalNoServer потому, что в твоём изначальном примере так и предполагалось видимо (но отличается от того что ты описывал словами).

        static async Task Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            Task task = null;
            for (int i = 0; ; i++)
            {
                Console.WriteLine(i);

                if (i != 0)
                {
                    cts.Cancel();
                    Thread.Sleep(10);
                    // task.Dispose();
                }

                cts = new();
                task = SignalNoServer(cts.Token);
            }
        }

        static async Task SignalNoServer(CancellationToken ct)
        {
            await Task.Yield(); // безусловный разрыв

            var v = Task.Delay(2000, ct);

            try
            {
                v.Wait(ct);
            }
            catch (OperationCanceledException ocex)
            {
            }

            if (!v.IsCanceled) Console.WriteLine("Обработка закончена " + DateTime.Now);
            else Console.WriteLine("Cancelled: " + DateTime.Now);
            //или другой вариант, в котором тоже нет отмены
            //if (!ct.IsCancellationRequested) Console.WriteLine("Обработка закончена " + DateTime.Now);
            v.Dispose();
        }


PS: Вместо таких городушек — можно было бы просто написать await.

        static async Task SignalNoServer(CancellationToken ct)
        {
            var v = Task.Delay(2000, ct);
            try
            {
                await v;
            }
            catch (OperationCanceledException) { }

            // if (ct.IsCancellationRequested) Console.WriteLine("Cancellation requested " + DateTime.Now);
            if (!v.IsCanceled) Console.WriteLine("Обработка закончена " + DateTime.Now);
            else Console.WriteLine("Cancelled: " + DateTime.Now);
            //или другой вариант, в котором тоже нет отмены
            //if (!ct.IsCancellationRequested) Console.WriteLine("Обработка закончена " + DateTime.Now);
            v.Dispose();
        }


PPS: Понятно, что мои исправления так же грязны как и исходный пример.