簡體   English   中英

在 CancellationTokenSource 上使用 CancelAfter 和循環

[英]Use CancelAfter on CancellationTokenSource with loop

我想創建一個實現超時的 class 助手。 因為任務一旦啟動就無法停止,我使用循環。 我想在不通過 GetAsync 的 CancellationToken 的情況下使用此模式。 我的問題是:這段代碼是你可以使用的最好的,還是循環會導致性能問題? 要了解示例:如果您更改https://reqres.in/api/users?delay=3 (延遲=4),您沒有超時。 如果沒有提出 CancelAfter 的另一個重要問題,為什么我的代碼仍然可以運行(請參閱 output )?

using System;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace RetryDemo {
    class Program {
        static void Main(string[] args) {
            Example();
            Console.ReadLine();
        }
        private static void Example() {
            Stopwatch Stopwatch = Stopwatch.StartNew();
            try {
                AppDomain.CurrentDomain.UnhandledException += (sender, e) => { Console.WriteLine(((AggregateException)e.ExceptionObject).InnerExceptions.Single().Message); };
                var source = new CancellationTokenSource();
                var token = source.Token;

                var task = Task.Run(async () => {
                    try {
                        using (token.Register(() => {
                            Console.WriteLine($"Timeout elapsed {Stopwatch.Elapsed}");
                        })) {
                            Task<HttpResponseMessage> message = GetPage("https://reqres.in/api/users?delay=4");
                            while (true) {
                                if (!token.IsCancellationRequested) {
                                    if (message.IsCompleted) {
                                        HttpResponseMessage messageSync = await message;
                                        Console.WriteLine(await messageSync.Content.ReadAsStringAsync());
                                    }
                                } else {
                                    break;
                                }
                                Thread.Sleep(200);
                                Console.Write(".");
                            }
                        }
                    } catch (Exception ex) {
                        Console.WriteLine(ex.Message);
                    }
                });

                source.CancelAfter(3500);


            } catch (Exception ex) {
                Console.Write(ex.Message);
            }
        }
        public static async Task<HttpResponseMessage> GetPage(string url) {
            Console.WriteLine($"Calling page{url}");
            HttpClient httpclient = new HttpClient();
            return await httpclient.GetAsync(url);//.ConfigureAwait(false);
        }
    }
}

我想在不通過 GetAsync 的 CancellationToken 的情況下使用此模式。

請記住,取消是合作的,所以這最終只會取消等待而不是操作本身。

它是您可以使用的最好的還是循環會導致性能問題?

一個完全正確的解決方案相當棘手,因為很容易忘記在正確的時間處理所有東西。 我建議使用我的AsyncEx library中的TaskExtensions.WaitAsync(CancellationToken) 它不使用輪詢; 相反,它使用Register在超時時立即取消等待。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM