I've googled around a lot and read different noob tutorials, but I don't think I understand what the proper thing to do is. Basically there is existing code that is synchronous that does something if the server is up and running. Sometimes, very rarely, the server takes longer to come up so I wanted to wrap it in some retry logic. I built a completely stupid console app to try to understand how async and await work a little bit and came up with this:
private static int counter = 0;
static void Main(string[] args)
{
DoIt();
Console.ReadLine();
}
static bool LongTask()
{
if (counter == 2)
{
Console.WriteLine("finally true");
Thread.Sleep(1000);
return true;
}
counter++;
Console.WriteLine("false");
Thread.Sleep(1000);
return false;
}
public static Task<bool> WrapperLongTask()
{
Console.WriteLine("wrapper called");
return Task.Run(() => LongTask());
}
public static async Task DoIt()
{
Console.WriteLine("hi");
var result = await WrapperLongTask();
while (result != true)
{
result = await WrapperLongTask();
Console.WriteLine("inside while loop");
}
Console.WriteLine($"outside while loop {result}");
Console.WriteLine("bye");
}
My LongTask function is representing my current function that does work that usually works the first time. Is it ok practice to then call this method with
Task.Run(() => LongTask())
Assuming that is 'ok', then I would basically create this in my actual code for my current method DoWork()
.
Task DoWorkAsync(....) {
return Task.Run(() => DoWork()
}
Basically just wrapping it in a Task.Run, changing the return type to Task. Then when I call this method later, I would do something like
var x = await DoWorkAsync;
// do more stuff with x
Is this way I should convert a previous sync method async?
pseudo code for DoWork(string directory, CancellationToken token)
var files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (var file in files) {
try {
token.ThrowIfCancellationRequested();
var fileName = Path.GetFileName(file);
// check if file already exists on server, if not, upload it
}
catch (Exception exception) {
// error handling
}
}
The short answer is No, you cannot convert all types of synchronous code to asynchronous simply by wrapping the operation with Task.Run
and making the method return Task
.
Usually, asynchronous code makes sense when the operation in consideration might invoke some IO operations (file system read/write, network or web access, database access ... etc.).
For example, if you have a method that reads some data from a file using synchronous methods like FileStream.Read
, and then does some CPU work on the contents of such file, then you can convert your method to be asynchronous by making it invoke FileStream.ReadAsync
instead and then asynchronously wait until ReadAsync
is done by using the await
keyword and then work on the contents of the file (of course you have to change the method to return Task
and to be async
).
The benefit in this case is that there is no thread waiting for the IO operation to complete and threads are expensive.
The benefit of not having threads waiting for IO operations to complete is very important in server applications like ASP.NET web sites where you expect a lot of simultaneous requests. However, for simple applications you might not want to bother with asynchronous code in the first place.
You can use Task.Run
if you want to run multiple CPU intensive operations on multiple CPU cores.
For example, if you have 4 CPU cores, it makes sense to create 4 tasks via Task.Run
to process some data. Consider the previous example, after you asynchronously wait for ReadAsync
to complete, you can split the result of the read to 4 parts (assuming that the data is relatively large), and create 4 tasks via Task.Run
, each will handle one part of the results. You can then asynchronously wait for the 4 tasks to complete using Task.WhenAll
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With