简体   繁体   中英

C# Understanding trouble with blocked UI and async / await vs. Task.Run?

I'm trying to do some asynchronous I/O work detached from UI thread. Somewhere I read:

  • 1) For CPU-bound code, you await an operation which is started on a background thread with the Task.Run method. Such as calculating prime numbers
  • 2) For I/O-bound code, you await an operation which returns a Task or Task inside of an async method. Such as waiting for network or database

So I did this:

// in windows form UI
private async void btnImport_Click(object sender, EventArgs e) {
    // [...]
    List<DataRow> rows = await importer.ImportDataAsync(123, 456);
    // [...]
}

// in Importer.ImportDataAsync:
public async Task<List<DataRow>> ImportDataAsync(int parent, int child, CancellationToken token = default(CancellationToken)) {

    // [...]
    List<DataRow> list = await RealImportFromDB(parent, child);
    return list;
    // [...]
}


public List<DataRow> RealImportFromDB(int p, int c) {

    List<DataRow> rowList;
    // here fetch the rows from DB over slow network
    // and return the row list
    return rowList;
}

With this approach the UI is blocked. If I call RealImportFromDB(...) like this

List<DataRow> l = await Task.Run(() => RealImportFromDB(parent, child));

the UI is not blocked but that conflicts with point 2) from above IMHO.

Where do I do things wrong?

Best regards, alex

public List<DataRow> RealImportFromDB(int p, int c) is a blocking call to the database, so to execute it Asynchronously, you have used the #1, where you have wrapped the call inside the Task.Run , which will free up Ui thread as expected

With this approach the UI is blocked. If I call RealImportFromDB(...)

It is since the method is not meant for the Asynchronous calling, it doesn't return a Task or Task<T> , which is the common requirement to make the Async call

Your code, await RealImportFromDB(parent, child) is not correct that's a compilation error, since you can only await the calls, which implements the GetAwaiter() internally check ( this and this ) and most common scenario is to return Task or Task<T> , there are other types too

Let's try to understand your two statements:

1) For CPU-bound code, you await an operation which is started on a background thread with the Task.Run method. Such as calculating prime numbers

This is what you are currently doing and is often done in clients to free up Ui thread, while processing takes place in background, but this would still use a Thread pool thread to do the execution, which is not as important as Ui thread, but still system resource

2) For I/O-bound code, you await an operation which returns a Task or Task inside of an async method. Such as waiting for network or database

To implement this you need a method, which is Async by default and returning a Task or Task<T> , such methods are part of all data frameworks, for every sync method nowadays there's a corresponding async method to initiate a asynchronous execution and they are the true IO calls, where they don't use a thread, since the processing is not in the same process, its across network / process boundary, so calling thread needn't wait, it just needs to come back and pick the result, when it arrives (any thread pool thread, not necessary the dispatching thread). Internally such methods use TaskCompletionSource<T> ( When to use TaskCompletionSource ), which has mechanism to notify the caller when the network call has accomplished

To implement this you need a method, which is Async by default and returning a Task or Task

Thanks a lot, this was my trouble. My RealImportFromDB(...) method is not an async method since it deals with an older, proprietary library that seems not ready for async calls.

Those were my thougths: with awaiting the result from ImportDataAsync(...) everything that is called within (eg RealImportFromDB(...) ) is dispatched from the UI thread also . So to say: everything within ImportDataAsync(...) is encapsulated / runs on in the second, non-blocking thread.

@others: yes you are right, the sample from my code won't even compile. Fiddled around a lot, so the code sample does not show everything what was changed, sorry for that :-}

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