gpt4 book ai didi

c# - ConfigureAwait(false) 和 IAsyncDisposable 的结构实现

转载 作者:行者123 更新时间:2023-12-05 03:26:28 25 4
gpt4 key购买 nike

我已经使用 ActionOnAsyncDispose 结构实现了 IAsyncDisposable,如下所示。我的理解是编译器在async using语句中不会装箱:

ActionOnDisposeAsync x = ...;
await using (x) {
...
}

对吗?到目前为止,一切都很好。我的问题是,当我像这样配置 await 时:

ActionOnDisposeAsync x = ...;
await using (x.ConfigureAwait()) {
...
}

x会被装箱吗?如果我将 ConfigureAwait 放在方法 Caf() 中会怎么样:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static public ConfiguredAsyncDisposable Caf(this ActionOnDisposeAsync disposable)
=> disposable.ConfigureAwait(false);

ActionOnDisposeAsync x = ...;
await using (x.Caf()) {
...
}

在那种情况下我可以避免装箱吗?我无法找到关于我的 using 变量究竟需要实现什么才能获得 ConfigureAwait 效果的文档。似乎也没有任何构建 ConfiguredAsyncDisposable 的公共(public)方式。

这是 ActionOnDisposeAsync:

public readonly struct ActionOnDisposeAsync : IAsyncDisposable, IEquatable<ActionOnDisposeAsync>
{
public ActionOnDisposeAsync(Func<Task> actionAsync)
{
this.ActionAsync = actionAsync;
}
public ActionOnDisposeAsync( Action actionSync)
{
this.ActionAsync = () => { actionSync(); return Task.CompletedTask; };
}
private Func<Task> ActionAsync { get; }

public async ValueTask DisposeAsync()
{
if (this.ActionAsync != null) {
await this.ActionAsync();
}
}

...
}

最佳答案

是的,ConfigureAwaitstruct disposables 上导致装箱。这是此行为的实验演示:

MyDisposableStruct value = new();
const int loops = 1000;
var mem0 = GC.GetTotalAllocatedBytes(true);
for (int i = 0; i < loops; i++)
{
await using (value.ConfigureAwait(false)) { }
}
var mem1 = GC.GetTotalAllocatedBytes(true);
Console.WriteLine($"Allocated: {(mem1 - mem0) / loops:#,0} bytes per 'await using'");

...其中 MyDisposableStruct 是这个简单的结构:

readonly struct MyDisposableStruct : IAsyncDisposable
{
public ValueTask DisposeAsync() => default;
}

输出:

Allocated: 24 bytes per 'await using'

Live demo .

为防止装箱发生,您必须创建一个自定义 ConfiguredAsyncDisposable -like struct,专门为您的结构量身定制。这是如何完成的:

readonly struct MyConfiguredAsyncDisposable
{
private readonly MyDisposableStruct _parent;
private readonly bool _continueOnCapturedContext;

public MyConfiguredAsyncDisposable(MyDisposableStruct parent,
bool continueOnCapturedContext)
{
_parent = parent;
_continueOnCapturedContext = continueOnCapturedContext;
}

public ConfiguredValueTaskAwaitable DisposeAsync()
=> _parent.DisposeAsync().ConfigureAwait(_continueOnCapturedContext);
}

static MyConfiguredAsyncDisposable ConfigureAwait(
this MyDisposableStruct source, bool continueOnCapturedContext)
{
return new MyConfiguredAsyncDisposable(source, continueOnCapturedContext);
}

现在运行与以前相同的实验,不对代码进行任何更改,不会导致分配。输出是:

Allocated: 0 bytes per 'await using'

Live demo .

关于c# - ConfigureAwait(false) 和 IAsyncDisposable 的结构实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71728812/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com