20

This might be a very stupid question, but I have the following lines of coding that convert RAW images to BitmapImages:

public async void CreateImageThumbnails(string imagePath, int imgId)
{
    await Task.Run(() => controlCollection.Where(x => x.ImageId == imgId)
                   .FirstOrDefault()
                   .ImageSource = ThumbnailCreator.CreateThumbnail(imagePath));
}

which calls this method CreateThumbnail()

public static BitmapImage CreateThumbnail(string imagePath)
{
    var bitmap = new BitmapImage();

    using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
    {
        bitmap.BeginInit();
        bitmap.DecodePixelWidth = 283;
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.StreamSource = stream;
        bitmap.EndInit();
    }

    bitmap.Freeze();

    GC.WaitForPendingFinalizers();
    GC.Collect();

    return bitmap;
}

When using async Void instead of async Task in my CreateImageThumbnails method, my application processes the images (29 of them) about 11 seconds faster than async Task. Why would this be?

async void async void

async task async task

The memory usage is much more using void, but the operation is completed much quicker. I have little knowledge of threading, this is why I am asking this question. Can someone please explain why this is happening?

Also I have done some research on when and when not to use async void, but I could not find an answer to my question. (I might just not have searched very well).

Thank you.

h.m.i.13
  • 353
  • 1
  • 6
  • 17
CareTaker22
  • 1,260
  • 3
  • 18
  • 36
  • 2
    Maybe this will help: https://stackoverflow.com/questions/12144077 – Helmut D Jul 03 '17 at 10:58
  • 1
    `async void` is fire and forget, so nothing keeps track of the async operation (or even makes sure it runs completely), while `async Task` actually keeps a track that can be awaited on. – poke Jul 03 '17 at 10:58
  • Do you await the task when you are using Task? – Magnus Jul 03 '17 at 10:59
  • 1
    @Magnus Yes, when I call `CreateImageThumbnails` using `Task`, I await it. – CareTaker22 Jul 03 '17 at 10:59
  • 4
    If you dont await it, it would be same as using void. – Magnus Jul 03 '17 at 11:00
  • @Magnus Exactly, but it then gives me the normal "Because this call is not awaited..." warning. I could use it just like that, but I want to know why using *void* is quicker than *Task* :) – CareTaker22 Jul 03 '17 at 11:02
  • It is not a requirement, you can avoid awaiting. In much cases it should be awaited that's why the compiler warn you. – Serg046 Jul 03 '17 at 11:04
  • 1
    Not related to the question but bear in mind that `FirstOrDefault()` could throw a `NullReferenceException` if it doesn't find a match in `controlCollection`. If you are sure it won't happen, you can still simplify it calling `controlCollection.First(x => x.ImageId == imgId).ImageSource = ...` – Anderson Pimentel Jul 03 '17 at 12:05

1 Answers1

13

When you call an async void method, or call an async Task method without awaiting it (if the called method contains an await, so it doesn't block), your code will continue right away, without waiting for the method to actually complete. This means that several invocations of the method can be executing in parallel, but you won't know when they actually complete, which you usually need to know.

You can take advantage of executing in parallel like this, while also being able to wait for all the invocations to complete by storing the Tasks in a collection and then using await Task.WhenAll(tasks);.

Also keep in mind that if you want to execute code in parallel, you have to make sure it's safe to do it. This is commonly called "thread-safety".

svick
  • 236,525
  • 50
  • 385
  • 514