简体   繁体   English

如果实际上不需要结果,则用于TaskCompletionSource的通用类型参数

[英]What generic type argument to use for TaskCompletionSource if no result is actually needed

If we want to create a TaskCompletionSource<T> based Task that has no Result we still need to provide a T and set a dummy value. 如果我们要创建一个基于TaskCompletionSource<T>的没有ResultTask ,我们仍然需要提供一个T并设置一个虚拟值。 Like this: 像这样:

Task SomethingAsync() {
 var tcs = new TaskCompletionSource<?>();
 tcs.SetResult(default(?)); //Can happen later as well, this is for demo purposes.
 return tcs.Task;
}

What's the best type to use for T from a performance standpoint? 从性能的角度来看,最适合T类型是什么?

It seems hard to answer that question purely from running a micro benchmark. 仅仅通过运行微型基准测试似乎很难回答这个问题。 I imagine the answer depends on the rest of the application. 我想答案取决于应用程序的其余部分。 For example, if we use TaskCompletionSource<bool> that will cause the JIT to generate specialized code and cause memory usage. 例如,如果我们使用TaskCompletionSource<bool> ,这将导致JIT生成专用代码并导致内存使用。 But it will not add memory usage if the app already uses boolean based tasks. 但是,如果应用程序已使用基于布尔的任务,则不会增加内存使用量。 If we use TaskCompletionSource<object> we might use more memory for each task (or not depending on the runtime). 如果我们使用TaskCompletionSource<object>我们可能会为每个任务使用更多的内存(或者不依赖于运行时)。

That's why I think a benchmark alone cannot answer the question and it must be answered by reasoning as well. 这就是为什么我认为仅凭基准无法回答问题,也必须通过推理来回答。

If you really want the best possible solution, you need to declare an empty struct. 如果您确实想要最好的解决方案,则需要声明一个空结构。 This way, the system won't have to reserve any space for the payload. 这样,系统将不必为​​有效负载保留任何空间。 This is actually what is done in the base class library: 这实际上是在基类库中完成的操作:

https://referencesource.microsoft.com/#System.Core/System/Threading/Tasks/TaskExtensions.cs,6e36a68760fb02e6,references https://referencesource.microsoft.com/#System.Core/System/Threading/Tasks/TaskExtensions.cs,6e36a68760fb02e6,引用

private struct VoidResult { }

From there, you can use TaskCompletionSource<VoidResult> , and TrySetResult(default(VoidResult)) to mark the task as completed. 从那里,您可以使用TaskCompletionSource<VoidResult>TrySetResult(default(VoidResult))将任务标记为已完成。

That said, it saves a tiny bit of memory, but I don't think it has any impact on execution time (even at nanoseconds level). 也就是说,它节省了一点点的内存,但是我认为它不会对执行时间产生任何影响(即使是在纳秒级)。 Whether you use a TaskCompletionSource<byte> (one byte reserved for the payload) or TaskCompletionSource<object> (four bytes reserved for the payload), a 32 bit CPU is still able to do the assignment in a single operation. 无论您使用TaskCompletionSource<byte> (为有效负载保留一个字节)还是TaskCompletionSource<object> (为有效负载保留四个字节),一个32位CPU仍可以在单个操作中进行分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM