是否有必要检查 `ValueTask.IsCompleted` 的性能?
Is it necessary to check `ValueTask.IsCompleted` for performance?
- 案例 1:
bool result = await DoAsync();
- 案例 2:
ValueTask<bool> task = DoAsync();
bool result = task.IsCompleted ? task.Result : await task;
上面有case 1
和case 2
,
谁能说 case 2
对性能(cpu、内存等)更好?
或者,task.IsCompleted
只是重复和多余的吗?
情况 1 没问题。如果你根本不使用 await
,你会使用 task.IsCompeted。
要真正确定,您需要使用合适的基准进行衡量。但是,我不会 期望 这会产生任何重大影响,因为 await
已经 确实如此 - 尽管通过 GetAwaiter()
(不分配)。它实际上会使真正的异步场景 变得更糟 。
类似于此优化的东西在库代码中很常见,但通常用于完全避免状态机结果是很多时候可能是同步的;例如:
var pending = DoAsync(); // note: not awaited; this is a [Value]Task[<T>]
return pending.IsCompletedSuccessfully
? new ValueTask<Foo>(PostProcess(pending.Result))
: Awaited(pending);
static async ValueTask<Foo> Awaited(ValueTask<Bar> pending)
=> PostProcess(await pending.ConfigureAwait(false));
这里的关键点是原始方法在这种情况下是而不是async
,所以我们只在真正的异步中支付任何async
开销路径(或在失败情况下,标准化错误堆栈)。
这里有一个 sharplab.io
link 显示了此优化的进展情况;在右侧,您可以看到未使用 async
的优化版本,结果为:
public ValueTask<Foo> ExampleAsync()
{
ValueTask<Bar> pending = DoAsync();
if (!pending.IsCompletedSuccessfully)
{
return <ExampleAsync>g__Awaited|0_0(pending);
}
return new ValueTask<Foo>(PostProcess(pending.Result));
}
Awaited
方法,不过是全部:
[AsyncStateMachine(typeof(<<ExampleAsync>g__Awaited|0_0>d))]
[CompilerGenerated]
internal static ValueTask<Foo> <ExampleAsync>g__Awaited|0_0(ValueTask<Bar> pending)
{
<<ExampleAsync>g__Awaited|0_0>d stateMachine = default(<<ExampleAsync>g__Awaited|0_0>d);
stateMachine.pending = pending;
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<Foo>.Create();
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <<ExampleAsync>g__Awaited|0_0>d : IAsyncStateMachine
{
public int <>1__state;
public AsyncValueTaskMethodBuilder<Foo> <>t__builder;
public ValueTask<Bar> pending;
private ConfiguredValueTaskAwaitable<Bar>.ConfiguredValueTaskAwaiter <>u__1;
private void MoveNext()
{
int num = <>1__state;
Foo result;
try
{
ConfiguredValueTaskAwaitable<Bar>.ConfiguredValueTaskAwaiter awaiter;
if (num != 0)
{
awaiter = pending.ConfigureAwait(false).GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(ConfiguredValueTaskAwaitable<Bar>.ConfiguredValueTaskAwaiter);
num = (<>1__state = -1);
}
result = PostProcess(awaiter.GetResult());
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
<>t__builder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
- 案例 1:
bool result = await DoAsync();
- 案例 2:
ValueTask<bool> task = DoAsync();
bool result = task.IsCompleted ? task.Result : await task;
上面有case 1
和case 2
,
谁能说 case 2
对性能(cpu、内存等)更好?
或者,task.IsCompleted
只是重复和多余的吗?
情况 1 没问题。如果你根本不使用 await
,你会使用 task.IsCompeted。
要真正确定,您需要使用合适的基准进行衡量。但是,我不会 期望 这会产生任何重大影响,因为 await
已经 确实如此 - 尽管通过 GetAwaiter()
(不分配)。它实际上会使真正的异步场景 变得更糟 。
类似于此优化的东西在库代码中很常见,但通常用于完全避免状态机结果是很多时候可能是同步的;例如:
var pending = DoAsync(); // note: not awaited; this is a [Value]Task[<T>]
return pending.IsCompletedSuccessfully
? new ValueTask<Foo>(PostProcess(pending.Result))
: Awaited(pending);
static async ValueTask<Foo> Awaited(ValueTask<Bar> pending)
=> PostProcess(await pending.ConfigureAwait(false));
这里的关键点是原始方法在这种情况下是而不是async
,所以我们只在真正的异步中支付任何async
开销路径(或在失败情况下,标准化错误堆栈)。
这里有一个 sharplab.io
link 显示了此优化的进展情况;在右侧,您可以看到未使用 async
的优化版本,结果为:
public ValueTask<Foo> ExampleAsync()
{
ValueTask<Bar> pending = DoAsync();
if (!pending.IsCompletedSuccessfully)
{
return <ExampleAsync>g__Awaited|0_0(pending);
}
return new ValueTask<Foo>(PostProcess(pending.Result));
}
Awaited
方法,不过是全部:
[AsyncStateMachine(typeof(<<ExampleAsync>g__Awaited|0_0>d))]
[CompilerGenerated]
internal static ValueTask<Foo> <ExampleAsync>g__Awaited|0_0(ValueTask<Bar> pending)
{
<<ExampleAsync>g__Awaited|0_0>d stateMachine = default(<<ExampleAsync>g__Awaited|0_0>d);
stateMachine.pending = pending;
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<Foo>.Create();
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <<ExampleAsync>g__Awaited|0_0>d : IAsyncStateMachine
{
public int <>1__state;
public AsyncValueTaskMethodBuilder<Foo> <>t__builder;
public ValueTask<Bar> pending;
private ConfiguredValueTaskAwaitable<Bar>.ConfiguredValueTaskAwaiter <>u__1;
private void MoveNext()
{
int num = <>1__state;
Foo result;
try
{
ConfiguredValueTaskAwaitable<Bar>.ConfiguredValueTaskAwaiter awaiter;
if (num != 0)
{
awaiter = pending.ConfigureAwait(false).GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(ConfiguredValueTaskAwaitable<Bar>.ConfiguredValueTaskAwaiter);
num = (<>1__state = -1);
}
result = PostProcess(awaiter.GetResult());
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
<>t__builder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}