简体   繁体   中英

Is there any difference between normal lambda and async lambda below?

Assume I have a library as follows for both non-UI based apps (ASP.NET) and UI based apps (WinForm and WPF). Unfortunately I cannot avoid mixing IO-bound work and CPU-bound work but I let the consumers invoke DummyWorkAsync via Task.Run or not based on their application types (non-UI or UI based apps).

class DummyService
{
  public static async Task<int> DummyWorkAsync()
  {
    // Do some I/O first.
    await Task.Delay(1000);

    // Tons of work to do in here!
    for (int i = 0; i != 10000000; ++i)
      ;

    // Possibly some more I/O here.
    await Task.Delay(1000);

    // More work.
    for (int i = 0; i != 10000000; ++i)
      ;

    return 0;
  }
}

This allows UI-based consumer to properly use Task.Run to call the service, while ASP.NET clients would just call the method directly as follows.

private async void MyButton_Click(object sender, EventArgs e)
{
  await Task.Run(() => DummyService.DummyWorkAsync());
}

public class Home: Controller
{
  public async Task<ActionResult> IndexAsync()
  {
    var result = await DummyService.DummyWorkAsync();
    return View(result);
  }
}

Question

I am interested in the UI-based apps. Is there any difference if I use

private async void MyButton_Click(object sender, EventArgs e)
{
  await Task.Run(async () => await DummyService.DummyWorkAsync());
}

rather than

private async void MyButton_Click(object sender, EventArgs e)
{
  await Task.Run(() => DummyService.DummyWorkAsync());
}

?

No, there is no (significant) difference. You are basically asking what's the difference between

static Task<int> Something() {
    return SomethingAsync();
}

and

static async Task<int> Something() {
    return await SomethingAsync();
}

Except in your case there is one more wrapping task ( Task.Run ), so differences in exceptions propagation for example which you may find in another questions on the same issue are not relevant in this case.

Because of that - just use

await Task.Run(() => DummyService.DummyWorkAsync());

That said, reasons for doing that are not that clear. Since your IO goes first - you can use ConfigureAwait(false) to prevent returning control to current synchronization context (which is good practice for libraries anyway). In that case, after your first await the rest (heavy CPU work) will be executed on thread pool thread (with default scheduler at least), so you won't need to use Task.Run in the first place:

public static async Task<int> DummyWorkAsync()
{
    // Do some I/O first.
    await Task.Delay(1000).ConfigureAwait(false);

    // Tons of work to do in here!
    // no problem, we are not on UI thread anyway
    for (int i = 0; i != 10000000; ++i)
        ;

    // Possibly some more I/O here.
    await Task.Delay(1000).ConfigureAwait(false);

    // More work.
    for (int i = 0; i != 10000000; ++i)
       ;

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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