为什么取消 Cosmos 查询需要这么长时间?

Why does it take so long to cancel a Cosmos Query?

我正在尝试使用 NuGet 包 Microsoft.Azure.Cosmos (3.13.0) 的取消标记来取消 cosmos 查询。

谁能帮忙解释一下为什么取消需要这么长时间?

此测试显示取消需要 2000+ 毫秒。我原以为它会在我取消后几毫秒内失败。

00158: Reading next
00160: Read next
00188: Cancelling
02492: The operation was canceled.
public class CosmosCancelationTests
{
    private readonly ITestOutputHelper testOutputHelper;

    public CosmosCancelationTests(ITestOutputHelper testOutputHelper)
    {
        this.testOutputHelper = testOutputHelper;
    }

    [Fact]
    public async Task TestCancelationTime()
    {
        Stopwatch stopwatch = Stopwatch.StartNew();
        try
        {
            var client = new CosmosClient(
                "https://localhost:8081/",
                "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
            );
            var database = client.GetDatabase("CosmosDBPackage"); // Make sure this database is created in the cosmos instance
            var container = database.GetContainer("SampleEntity"); // Make sure this container is created in the database
                var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken = cancellationTokenSource.Token;
            using var feedIterator = container.GetItemLinqQueryable<SampleEntity>()
                .Where(x => false)
                .ToFeedIterator();
            if (feedIterator.HasMoreResults)
            {
                testOutputHelper.WriteLine($"{stopwatch.ElapsedMilliseconds:D5}: Reading next");
                var task = feedIterator.ReadNextAsync(cancellationToken);
                testOutputHelper.WriteLine($"{stopwatch.ElapsedMilliseconds:D5}: Read next");

                await Task.Delay(20);
                cancellationTokenSource.Cancel();
                testOutputHelper.WriteLine($"{stopwatch.ElapsedMilliseconds:D5}: Cancelling");
                await task;
            }
        }
        catch (CosmosOperationCanceledException e)
        {
            testOutputHelper.WriteLine($"{stopwatch.ElapsedMilliseconds:D5}: {e.Message}");
        }
    }
}

.NET 中的 CancellationTokens 是一种根据定义不会导致任何库立即停止其正在执行的操作的机制,它是一种合作取消。库将在安全时取消操作,并且不会导致损坏或无效状态。例如,HttpClient,当您调用 SendAsync 并且令牌取消时,如果客户端已经开始缓冲响应,它不会取消,它会等到它完成。

在查询的情况下,它将检查令牌,当它是安全的并且不会导致无效状态时,可能在请求在线时发生取消,或者正在聚合响应。

参考:https://docs.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads