为什么取消 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
我正在尝试使用 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