2016-10-29 4 views
0

Если мы хотим создать TaskCompletionSource<T> на основе Task, который не имеет Result нам еще нужно обеспечить T и установить фиктивное значение. Как это:Какой общий тип аргумента использовать для TaskCompletionSource, если результат не нужен на самом деле

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

Что лучший тип использовать для T с точки зрения производительности?

Кажется, трудно ответить на этот вопрос исключительно из запуска микро-теста. Я полагаю, что ответ зависит от остальной части приложения. Например, если мы используем TaskCompletionSource<bool>, что заставит JIT генерировать специализированный код и вызывать использование памяти. Но это не добавит использования памяти, если приложение уже использует задачи на основе boolean. Если мы используем TaskCompletionSource<object>, мы можем использовать больше памяти для каждой задачи (или не в зависимости от времени выполнения).

Вот почему я считаю, что только один контрольный тест не может ответить на вопрос, и на него также должны ответить рассуждения.

ответ

3

Если вы действительно хотите наилучшего решения, вам нужно объявить пустую структуру. Таким образом, системе не нужно резервировать место для полезной нагрузки. Это на самом деле то, что делается в библиотеке базовых классов:

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

private struct VoidResult { } 

Оттуда вы можете использовать TaskCompletionSource<VoidResult> и TrySetResult(default(VoidResult)) отметить задачу как завершенную.

Это говорит о том, что он сохраняет небольшую часть памяти, но я не думаю, что это влияет на время выполнения (даже на уровне наносекунд). Используете ли вы TaskCompletionSource<byte> (один байт, зарезервированный для полезной нагрузки) или TaskCompletionSource<object> (четыре байта зарезервированы для полезной нагрузки), 32-разрядный ЦП по-прежнему способен выполнять назначение за одну операцию.

+0

Хорошая идея. Интересно, будут ли байты, bool и VoidResult сохранять любые байты из-за того, как выполняется макет объекта. Объекты 8 байт выровнены на 64 бит (я думаю). Кроме того, это заставляет новый набор jitted-кода для каждой сборки, которая делает это. – boot4life

+0

@ boot4life Трудно ответить. 'TaskCompletionSource ' имеет одно поле (хранит 'Task ') и заполняет 4 байта ОЗУ на x86. Любая дополнительная полезная нагрузка вытесняет зарезервированное пространство для следующего выравнивания по 4 байта. Но я действительно не знаю, как обрабатываются 0 байтов, такие как 'VoidResult'. Если это сделано правильно (возможно, это так), то это означает, что система может хранить «TaskCompletionSource » в одном пространстве с 4 байтами (не считая заголовков, специфичных для CLR), тогда как «TaskCompletionSource » и «TaskCompletionSource » будут использовать 8 байты (из-за выравнивания) –

+1

В любом случае объект TaskCompletionSource не будет затронут, но размер задачи будет. В 4.6 я вижу одно поле «T result» в производном классе. Поэтому в идеале производная часть заканчивается пустым. – boot4life

 Смежные вопросы

  • Нет связанных вопросов^_^