Есть ли смысл возвращать ValueTask из метода, который внутренне ожидает некоторых задач - PullRequest
2 голосов
/ 28 января 2020

У меня есть метод asyn c, который выглядит примерно так:

async Task<int> ParseStream()
{
    var a = await reader.ReadInt32();
    var b = await reader.ReadInt32();
    return a + b;
}

Этот метод будет работать синхронно большую часть времени, поскольку данные уже готовы. Похоже, хорошая идея заменить тип возвращаемого значения на ValueTask, чтобы уменьшить выделение. Но это вызывает reader.ReadInt32() return Task.

Так что вопрос: есть ли смысл возвращать ValueTask из метода, который внутренне ожидает некоторые задачи?

Ответы [ 3 ]

1 голос
/ 28 января 2020

Изменение сигнатуры вашего метода для возврата ValueTask вместо Task:

async ValueTask<int> ParseStreamAsync()
{
    var a = await reader.ReadInt32Async();
    var b = await reader.ReadInt32Async();
    return a + b;
}

... имеет то преимущество, что вызывающие ваш метод методы будут избегать выделения объекта в случае, если оба Звонки на номер reader.ReadInt32Async будут выполняться синхронно. Но это не может быть большим преимуществом, потому что два вызова reader.ReadInt32Async могут по-прежнему выделять объект Task каждый, в зависимости от того, как реализован этот метод. Теоретически возможно, что некоторые общие Task<Int32> возвращаемые значения будут кэшироваться, но на практике это маловероятно. Было бы иначе, если бы возвращаемое значение было Task<bool>, при кэшировании только два возможных значения были бы дешевыми. Кэширование Task<TResult> объектов было единственным доступным способом сокращения выделения ресурсов до введения ValueTask s.

Так что, используя ValueTask вместо Task, можно разумно ожидать, что вы уменьшите объект ассигнования от 3 до 2 на каждый вызов, что не очень впечатляет, но и не незначительно.

0 голосов
/ 28 января 2020

Если вы не уверены, подходит ли оно для ValueTask<T>, возможно, это потому, что это не так.

Понимание почему, что и когда используется ValueTask

Вы можете кэшировать и ждать Task<T> столько раз, сколько захотите. У него есть только обратная сторона распределения кучи.

0 голосов
/ 28 января 2020

Да, потому что это одна часть шаблона. Это то, что вы показываете, не блокирует использование шаблона asyn c, поэтому, если вы не используете задачу в ответ, это должно быть блокирование.

...