12

Which would be a valid implementation of ValueTask please? Cache service returns data either from cache or DB.

public async ValueTask<IList<HrEmploymentDataCustom>> GetEmployeesFacts()
{
    try
    {
        var facts = (List<HrEmploymentDataCustom>) _memoryCache.Get("facts");
        return facts ?? await _accountService.GetEmploymentFacts(DetailsRequestType.All, null);
    }
    catch (Exception e)
    {
        var tc = new TelemetryClient();
        tc.TrackException(e);
        return null;
    }
}

Would this be: var employeesFacts = await _cacheService.GetEmployeesFacts();

or var employeesFacts = _cacheService.GetEmployeesFacts().Result;

Little bit confused here.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
sziszu
  • 490
  • 1
  • 6
  • 16
  • 9
    always `await` a Task if you can. Blocking with `.Result` is wasteful at best and deadlocks at worst. – Crowcoder Sep 20 '18 at 12:21
  • I prefer await, this way you have a better exception (if something's wrong)... .Result wraps all errors in AggregateException – Ferryzijl Sep 20 '18 at 12:22
  • Possible duplicate of [What is the difference between await Task and Task.Result?](https://stackoverflow.com/questions/27464287/what-is-the-difference-between-await-taskt-and-taskt-result) – Oram Sep 20 '18 at 12:22
  • Yeah, but what in case of Value return, is this smart enough to do not do it async (performance - wise)? – sziszu Sep 20 '18 at 12:23
  • @Oram No, a ValueTask is similar to a Task but it's not the same – Camilo Terevinto Sep 20 '18 at 12:23
  • @sziszu You may want to read: https://stackoverflow.com/a/43003779/2141621 – Camilo Terevinto Sep 20 '18 at 12:23
  • @sziszu yes, thats correct – Ferryzijl Sep 20 '18 at 12:24
  • @CamiloTerevinto I know there's a difference. You're right it's not a duplicate, but for the sake of knowing if you want to `await` or `.Result` the answer to that question is useful. – Oram Sep 20 '18 at 12:28

1 Answers1

40

Would this be:

var employeesFacts = await _cacheService.GetEmployeesFacts();

Typically yes.

or

var employeesFacts = _cacheService.GetEmployeesFacts().Result;

Little bit confused here.

NEVER EVER.

Let's unconfuse you.

First: value task is simply a task that is copied by value instead of reference. Do not use ValueTask unless you know the difference and have a reason to do so driven by an empirical performance study that indicates that regular tasks are a large contributor to collection pressure. Just use regular tasks almost all the time.

You don't change how you use a task based on whether it was copied by value or by reference. You await tasks, regardless.

You never use .Result on a task, regardless of whether it is a value or a reference. Why? Because suppose the task is not complete: then Result will wait synchronously for its completion. Suppose the final step of the workflow is currently in the queue of the current thread waiting to be dispatched. You just put that thread to sleep! Now the thread is sleeping, waiting for itself to wake it up, and so it will sleep forever. Never use .Result. It's the wrong thing to do almost always.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • This is what I thought, so is it worth in the case above to use ValueTask instead of Task? – sziszu Sep 20 '18 at 12:26
  • 12
    @sziszu: **Do an empirical performance study that determines whether tasks are a large contributor to unwanted collection pressure**. If yes, do the same study again using value tasks and see if it makes a difference. **Answer your question by doing science, not by asking strangers on the internet about the performance characteristics of programs they didn't write and have never run**. You wrote your program; test it! – Eric Lippert Sep 20 '18 at 12:28
  • 4
    Using `.Result` or `.Wait()` ( on a Task ) can be used if you know what you are doing ( For example having a working thread working with Tasks and IAsyncEnumerables ). I would say: Never use it unless you have to and you absolutely know what you are doing. – Felix K. Apr 30 '21 at 21:27