I'm working on a firmware update app and I'm trying to use Async/Await to avoid blocking the UI. The problem I'm facing is that the process of updating firmware requires a series of steps to occur in sequence (which is not asynchronous). Yet it looks like async is still the way to go when a UI is involved to avoid freezing the application. So how do we not block the UI, sequentially complete a long running series of tasks, and not eat up or waste threads?
Here's a non-async example to illustrate the problem:
public class FirmwareUpdateViewModel : ObservableObject
{
//ctor
public FirmwareUpdateViewModel()
{
// Process should start on page load
updateFirmware();
}
private void updateFirmware()
{
//...
DeviceHandshake();
SendMessage(Commands.RestartDevice);
GetFWFileData();
WaitForDevice(timeout);
SendMessage(PreliminaryData);
//...
}
}
My first attempt was to await Task.Run(() =>
everything:
public class FirmwareUpdateViewModel : ObservableObject
{
//ctor
public FirmwareUpdateViewModel()
{
updateFirmwareAsync();
}
private async void updateFirmwareAsync()
{
//...
await Task.Run(() => DeviceHandshakeAsync());
await Task.Run(() => SendMessageAsync(Commands.RestartDevice));
//...
}
}
The problem here besides the async void
is that because of the viral nature of Async, when I await inside DeviceHandshakeAsync
, plus if Task.Run()
is running on it's own thread then we are wasting a ton of threads.
I next tried dropping the Task.Run(() =>
and just awaiting each method, but as far as I know, the sub-methods will return when they encounter an internal await
and begin to run the next sub-method before the previous completes. And now I'm trying to run the firmwareUpdate method async but not awaiting the sub-methods in an attempt to keep them synchronous and fight the viral nature, but this blocks the UI:
public class FirmwareUpdateViewModel : ObservableObject
{
//ctor
public FirmwareUpdateViewModel()
{
Result = new NotifyTaskComplete<bool>(updateFirmwareAsync());
}
private async Task<bool> updateFirmwareAsync()
{
//...
DeviceHandshake();
SendMessage(Commands.RestartDevice);
//...
}
}
The problem here is obviously that without await
s we're running synchronously and on the UI thread. Nothing has "clicked" yet for me in understanding the right approach here. How do we do it right?
Edit: I realized I left out a big part of the problem...that the USB is handled by a 3rd party library that is synchronous. So I need to wrap those functions somehow to avoid blocking the UI:
public class FirmwareUpdateViewModel : ObservableObject
{
//ctor
public FirmwareUpdateViewModel()
{
// Don't block the UI with this
updateFirmware();
}
private void updateFirmware()
{
//...
// Run all non-blocking but sequentially
DeviceHandshake();
SendMessage(Commands.RestartDevice);
GetFWFileData();
WaitForDevice(timeout);
SendMessage(PreliminaryData);
//...
}
private void SendMessage(Command)
{
// Existing code, can't make async
USBLibrary.Write(Command);
}
}
This is why I'm so confused, because async wants to spread but I can't in between the constructor and end library.