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 awaits 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.