Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Saturday, July 19, 2014 6:44 PM | 1 vote
Hi,
I am trying to call a method which I don't really intend to wait for it to complete. So, I used Task.Factory.StartNew to call my method. All the method does is to write a line into a text file. What I observe is that the file never gets created or written to. What am I missing here? It never seems like it gets done in the background. How do I ensure that I call the method, not having to wait for it and yet it completes in the background. I don't want the main thread to be blocked in anyway.
static void Main(string[] args)
{
Console.WriteLine("Before caling WritingToFile");
Task.Factory.StartNew(() => WritingToFile("Don't wait"));
Console.WriteLine("After caling WritingToFile");
}
public static async void WritingToFile(string strLine)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\test\WritingToFile.txt"))
{
for (int i = 0; i < 10; i++)
{
file.WriteLine(strLine);
}
}
}
All replies (16)
Saturday, July 19, 2014 10:26 PM âś…Answered
To rephrase, I have an async void method named WritingToFile, when I call it, for some reason, the file never gets created / written to.
Well, are you certain that you know what you're doing?
It definitely runs at the background but not because the method is marked as async in fact, it runs synchronously inside the thread.
The async keyword does nothing on its own so if you want to actually make it run asynchronously you need to do few changes.
- Change the method to return Task rather than void.
- Use the async version of WriteLine which is WriteLineAsync and await it.
I've made few changes to make things more noticeable.
You will notice that in the following example the same thread is reused for both of the tasks which means the running task doesn't block the thread and when it's not possible to reuse it then it will use another one.
static void Main(string[] args)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Before caling WritingToFile");
Task x = WritingToFile(@"d:\WritingToFile1.txt", 1000);
Task y = WritingToFile(@"d:\WritingToFile2.txt", 2000);
// Run all of the tasks until all of them are completed
Task.WhenAll(x, y);
Console.WriteLine("After caling WritingToFile");
Console.ReadKey(true);
}
public static async Task WritingToFile(string fileName, int timeout = 1000)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(fileName))
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(timeout);
await file.WriteLineAsync("Don't wait");
Console.WriteLine("[Thread: {0}] {1}: {2}", Thread.CurrentThread.ManagedThreadId, fileName, i);
}
}
}
Regards, Eyal Shilony
Saturday, July 19, 2014 6:55 PM
Hi,
Take a look here: http://stackoverflow.com/questions/15522900/how-to-safely-call-an-async-method-in-c-sharp-without-await
I hope it helps.
Saturday, July 19, 2014 7:22 PM
thanks, but my method does not return anything, it is a void method. How do I accomplish it given your suggestion?
Saturday, July 19, 2014 7:29 PM
To rephrase, I have an async void method named WritingToFile, when I call it, for some reason, the file never gets created / written to.
Saturday, July 19, 2014 8:23 PM
I think this can be considered as resolved. Basically, the Main program completed before even letting the async method complete. All I did was to put a delay in Main after calling the async method, the metod gets called asynchornously, the main thread does not wait and contiunes to execute the delay loop and finally I see the file being created and written to.
Thanks
Saturday, July 19, 2014 10:31 PM
I think this can be considered as resolved. Basically, the Main program completed before even letting the async method complete. All I did was to put a delay in Main after calling the async method, the metod gets called asynchornously, the main thread does not wait and contiunes to execute the delay loop and finally I see the file being created and written to.
Thanks
No the method does not being called asynchronously it's called synchronously in the background, a major difference!
Regards, Eyal Shilony
Saturday, July 19, 2014 11:00 PM
thanks, what if the method I was calling does not have any async functions like WriteLineAsync. In other words, there could be a method that is doing some processing, but all I want to do is call it without blocking the main thread and let it run to compleition. So the main thread and the task thread run independently of each other on separate threads. On my original code, when I print the threadIds of the Main the the called method I always get 1 for the Main and 3 for the method.
Below is the code with the delay. It looks like the main and WritingToFile are run independently of each other and on separate threads.
static void Main(string[] args)
{
Console.WriteLine("*******MAIN Thread******* :: " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("MAIN Before caling WritingToFile");
Task.Factory.StartNew(() => WritingToFile("Something"));
Console.WriteLine("MAIN After caling WritingToFile");
Console.WriteLine("*******MAIN Thread******* :: " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("MAIN Starting Delay Loop in Main thread");
for (int i = 0; i < 5; i++)
{
Thread.Sleep(3);
}
Console.WriteLine("MAIN Ending Delay Loop in Main thread");
}
public static async void WritingToFile(string strLine )
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("********TASK START async Writing to file");
Console.WriteLine("*******TASK THREAD *******:: " + Thread.CurrentThread.ManagedThreadId);
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\test\MyFile.txt"))
{
for (int i = 0; i < 5; i++)
{
string strWLine = "TASK Writing to file " + " :: " + i + " :: " + strLine;
file.WriteLine(strWLine);
Console.WriteLine(strWLine);
Console.WriteLine("*******TASK THREAD *******:: " + Thread.CurrentThread.ManagedThreadId);
}
}
Console.WriteLine("*******TASK THREAD *******:: " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("********TASK END async Writing to file");
}
################OUTPUT######################
***************MAIN Thread*************** :: 1
MAIN Before caling WritingToFile
MAIN After caling WritingToFile
***************MAIN Thread*************** :: 1
MAIN Starting Delay Loop in Main thread
********TASK START async Writing to file
***************TASK THREAD ***************:: 3
TASK Writing to file :: 0 :: Something
***************TASK THREAD ***************:: 3
TASK Writing to file :: 1 :: Something
***************TASK THREAD ***************:: 3
TASK Writing to file :: 2 :: Something
***************TASK THREAD ***************:: 3
TASK Writing to file :: 3 :: Something
***************TASK THREAD ***************:: 3
TASK Writing to file :: 4 :: Something
***************TASK THREAD ***************:: 3
***************TASK THREAD ***************:: 3
********TASK END async Writing to file
MAIN Ending Delay Loop in Main thread
Press any key to continue . . .
Sunday, July 20, 2014 12:30 AM
If you want to use threading directly and guarantee that each thing runs in a separate thread that's fine but you really don't need to use the async modifier on the method because it does nothing useful on its own.
You need to understand that running something independently from another thing doesn't mean it runs asynchronously.
You really don't need the loop and it's actually incorrect to do so because you're assuming that each IO write will take less than 3ms which in fact can take longer and then it won't write everything by the time the delay ends so just replace it with Console.ReadKey(true).
Regards, Eyal Shilony
Sunday, July 20, 2014 12:50 AM
I think I am beginning to understand your point of view. In the code I have, it is really starting a task on a new thread and as a result it lets the main running thread to continue. Async would be more apt if it the method was using an async method like WriteLineAsync and await it. I also used the while loop for just as an example.
So for my case where I read some data continually on one thread and want to process it on another thread as and when it comes without blocking the callign thread, what would you recommend? I think starting the task on a new thread would be the best way to deal with it. Please suggest.
Sunday, July 20, 2014 3:02 AM
Well, it really depends whether the operation you're doing is IO bound or CPU bound.
When the application is waiting most of the time for something else to come in like a client waiting for a server then async IO is desired because the client can do other things while waiting for say a response or downloading a file.
When most of your work is CPU heavy tasks such as data processing like encoding or calculations then async not only makes the program more complex but it will also degrade performance.
In your case I don't see the value in async so spawning a new thread is just fine.
I usually start async operations using Task.Run so I do spawn additional thread rather than doing it directly on the UI thread but then again it really depends, depending on the System Requirements and the time it takes for the operation(s) to complete.
Regards, Eyal Shilony
Sunday, July 20, 2014 3:10 AM
Thank you so much. Your answers were very informative. Appreciate it.
Sunday, July 20, 2014 3:14 AM
Thank you so much. Your answers were very informative. Appreciate it.
You welcome. :)
Regards, Eyal Shilony
Monday, July 21, 2014 6:50 PM
The main reason is that your application is terminating, probably before the task even begins. If you add a Console.ReadLine() after the WriteLine call, then the file should be written.
Monday, July 21, 2014 9:40 PM
Hi,
I am trying to call a method which I don't really intend to wait for it to complete. So, I used Task.Factory.StartNew to call my method. All the method does is to write a line into a text file. What I observe is that the file never gets created or written to. What am I missing here? It never seems like it gets done in the background. How do I ensure that I call the method, not having to wait for it and yet it completes in the background. I don't want the main thread to be blocked in anyway.
Why don't you use Stream.WriteAsync()? It was designed with this purpose in mind.
Tuesday, July 22, 2014 12:32 AM
Thanks, I wanted to know how to call a method without blocking the thread that was calling the method. In trying to ask that, I chose a bad example that had a write to a file. Your suggestion is correct, if I had to write to a file asynchronously, I can use it. But what I really needed to know was to be able to call a method, not block the calling thread and not worry about the results of the called method.
Friday, May 4, 2018 11:30 AM
Thanks Eyal for your reply. It is easy to understand how we can perform the other action without interrupting Main thread.
But i have a question here if we remove that task.delay from WriteToFile method that time main thread works for all requests.
So its mean when we are working in actual code we should use Task.delay
i dont think it is good choice.
Vidit