I have a console application with have two threads as:
public static async void Thread1()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Thread1 " + i);
await MyFunc();
}
}
public static async void Thread2()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Thread2 " + i);
await MyFunc();
}
}
public static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args)
{
Console.WriteLine("Before start thread");
Thread tid1 = new Thread(Thread1);
Thread tid2 = new Thread(Thread2);
tid1.Start();
tid2.Start();
}
public static async Task MyFunc()
{
//do something
}
However, when the application run and terminates, it seems that only each thread is run just once as I see only below things in output:
Before start thread
Thread1 0
Thread2 0
//some thing from MyFunc
I expect or rather wannt to run each thread till the for loop.It seems to me that the for loop continues to run despite the await.
If yes, what could be other probable approach.
Any leads would be helpful.
You aren't doing anything to wait for the threads. The main routine will just continue on until it returns to the O/S, which will kill the process and any child threads. Since you aren't doing anything else, this happens almost immediately, cutting both threads' lives short.
If you want to wait for the threads to finish, you can refer to this answer and write some variation of
while (thread1.IsAlive || thread2.IsAlive)
{
//Do something to wait
}
...before exiting.
That being said, you should probably using Tasks instead of threads, e.g.
public static async Task Task1()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Task1 " + i);
await MyFunc();
}
}
public static async Task Task2()
{
for (int i = 0; i < 100; i++)
{
Debug.WriteLine("Task2 " + i);
await MyFunc();
}
}
And then to execute and wait for both of them:
Task.WaitAll
(
new[]
{
Task1(),
Task2()
}
);
See this code in action on DotNetFiddle
See also What is the difference between tasks and threads?
You seem to have a lot of confusion about the role of threads and tasks, so it's a good idea to read up about it. Steven Cleary has a nice write-up about this. "There Is No Thread"
From the comments, it seems that your actual intention here is to run two async tasks in parallel, then to wait until they are both finished.
If you want to wait for two async tasks to complete in parallel, make sure your async methods actually return Task then:
Task task1 = DoSomethingAsync(); //don't await
Task task2 = DoSomethingElseAsync(); //don't await
then you can wait asynchronously for Task.WhenAll:
await Task.WhenAll(task1,task2);
You really don't need to be involving Thread at all.
Use async Task instead of async void
private static async Task MainAsync(string[] args)
{
Console.WriteLine("Before start thread");
var task1 = Thread1();
var task2 = Thread2();
var taskList = new [] { task1, task2 };
Task.WaitAll(taskList);
}
Related
This question already has answers here:
Why Async Method always blocking thread?
(4 answers)
Closed 1 year ago.
I am trying to call this async method from a console application. I was expecting the part "a" of my method to run asynchronously while the execution awaits for the ReturnsString() but that is not the case, everything seems to be executed synchronously. I am failing to understand why.
sorry for my bad english.
dotnet fiddler
output
public class AsyncAwaitExe3
{
public async Task<string> DoAsync()
{
string toReturn = "";
Console.WriteLine("I'm here A");
//a
for (int i = 0; i < 30; i++)
{
Console.WriteLine($"inside for {i}");
Thread.Sleep(1000);
}
//b
Console.WriteLine("I'm here B");
toReturn = await ReturnsString();
//c
Console.WriteLine("I'm here C");
return toReturn;
}
public async Task<string> ReturnsString()
{
Console.WriteLine("I'm here D");
await Task.Delay(2000);
Console.WriteLine("I'm here E");
return "sharp sword";
}
}
static void Main(string[] args)
{
AsyncAwaitExe3 exe3 = new AsyncAwaitExe3();
Console.WriteLine(exe3.DoAsync());
Console.ReadKey();
}
Section a is synchronous code-- there is nothing about it that returns a task while it continues to run. If you want it to be async, you can break it into a different, async method. Then wait for both to complete using Task.WhenAll.
Also, you have to using Task.Delay() instead of Thread.Sleep(). Task.Delay returns a task which you can await; Thread.Sleep just blocks the thread synchronously.
async Task RunSectionA()
{
Console.WriteLine("I'm here A");
for (int i = 0; i < 30; i++)
{
Console.WriteLine($"inside for {i}");
await Task.Delay(1000);
}
}
public async Task<string> DoAsync()
{
var taskA = RunSectionA();
var taskB = ReturnsString();
await Task.WhenAll(taskA, taskB);
return await taskB;
}
This question already has answers here:
How to delay 'hot' tasks so they can processed in a set order
(2 answers)
Closed 4 years ago.
I need to first create new task then do some remaining work and then start the task that works with its result.
Simplified example:
static int value;
static async Task work1()
{
do
{
int i;
for (i = 0; i < 10000000; i++) {} // some calculations
Console.WriteLine("result1: " + value + " i: " + i);
await Task.Delay(2000).ConfigureAwait(false);
} while (condition);
}
static async Task work2()
{
do
{
int i;
for (i = 0; i < 10000000; i++) {} // some calculations
Console.WriteLine("result2: " + value + " i: " + i);
await Task.Delay(2000).ConfigureAwait(false);
} while (condition);
}
static void Main(string[] args)
{
Task task;
int tempvalue = 100;
if (condition1)
{
tempvalue *= 10;
task = new Task(() => work1());
} else
{
tempvalue -= 5;
task = new Task(() => work2());
}
if (tempvalue > 100)
{
value = 5;
} else
{
value = tempvalue;
}
task.Start();
// immediately do remaining work
}
this code does exactly what I need but compiler shows following warning:
Warning CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
on line:
Task task = new Task(() => work());
should I rather use it like so? Is there any difference?
Task task = new Task(async () => await work());
This is not a duplicate of How to delay 'hot' tasks so they can processed in a set order because after task.Start(); it should do remaining work immediately.
Func<Task> f = () => work();
// do stuff
f(); // blocks thread until work1() or work2() hits await
// do remaining work
The async keyword means that the task within your task is asynchronous and using await will mean that you want to wait for the method work to finish.
You could also use Task.Wait() in order to wait for the method to finish it's execution.
But using async await is the better way to do it because it's not blocking the main thread.
I got a requirement where I need to process two Threads simultaneously in a ForLoop.
For Example :
private void BtnThreading_Click(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
Thread thread1 = new Thread(ProcessA);
thread1.Start();
thread1.Join();
Thread thread2 = new Thread(ProcessB);
thread2.Start();
}
}
private void ProcessA()
{
Thread.Sleep(10000);
}
private void ProcessB()
{
Thread.Sleep(20000);
}
For the First Time in the for-loop,Let's say the ProcessA() takes 10 Seconds to complete and I need to wait till the ProcessA() to finish using thread1.Join(); to Start Processing ProcessB().Later the ProcessB() starts and it will take 20 seconds to finish.
So,In the mean while ProcessA() again starts and thread1.Join(); statement will wait until ProcessA() finishes.Here I need to wait also for the previous ProcessB() to finish.
so finally,I want the ProcessB() to wait for the Previous Thread of ProcessB()
Sorry for my Bad English !!! :)
Unless your really need to do low level programming you should not use Thread objects directly. Each thread is quite expensive in terms of resources. Instead .NET provides several high level abstractions to do asynchronous and parallel programming. Your loop can be built using async and await and will then execute on thread pool threads. Here is an example:
Instead of using Thread.Sleep to simulate delay you have to use Task.Delay:
async Task ProcessA() {
await Task.Delay(10000);
}
async Task ProcessB() {
await Task.Delay(20000);
}
The loop:
var task = Task.Delay(0); // No operation task to simplify loop.
for (var i = 0; i < 20; i += 1) {
await ProcessA();
await task;
task = ProcessB();
}
await task;
It looks like you don't really need ProcessA to execute in a different thread at all - but you do need to keep track of your previous ProcessB thread. So something like:
Thread previousThread = null;
for (int i = 0; i < 20; i++)
{
ProcessA();
if (previousThread != null)
{
previousThread.Join();
}
previousThread = new Thread(ProcessB);
previousThread.Start();
}
// Possibly join on previousThread here too
Note that your method name suggests that you're doing this in a UI thread - which you really, really shouldn't. Don't block the UI thread for any length of time - and remember that Join is a blocking call.
You can give this code a try, but again it is not production ready..!!!
Thread thread1 = null;
Thread thread2 = null;
private void BtnThreading_Click(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
thread1 = new Thread(ProcessA);
thread1.Start();
thread1.Join();
if (thread2 != null)
thread2.Join();
thread2 = new Thread(ProcessB);
thread2.Start();
}
}
Previously, when making a looping task it would run perfectly the first time and fall apart because of the timing problems, such as the functions of one individual task would start running faster than another, even though it was programmed to come before that task.
So my idea to figure out a way to repeat the events of a task once the delays(times) have ended, in my head it would go something like this:
private async Task programCore()
{
int n = 1000;
for (int i = 0; i < n; )
{
FirstThing();
await Task.Delay(2100);
SecondThing();
await Task.Delay(2200);
ThirdThing();
await Task.Delay(2300);
}
////////////////////////////////////////////////////////////////////////////
else if (programCore.TasksHaveAllTimedOut) // Idealistic code.
{
programCore.Restart();
}
}
Is something like this possible? If not, is there a better way to do it?
How about this:
private async Task programCore()
{
int n = 1000;
for (int i = 0; i < n; )
{
await FirstThing();
await SecondThing();
await ThirdThing();
}
}
private async Task FirstThing()
{
// Do something here
}
private async Task SecondThing()
{
// Do something here
}
private async Task ThirdThing()
{
// Do something here
}
This has the effect that it runs FirstThing, waits for it to finish, then runs SecondThing, waits for it to finish, then finally runs ThirdThing and waits for it to finish before repeating the loop.
I believe #CodingGorilla has the right idea. Your code should look something like this (using CancellationTokens for timeouts):
private async Task programCore()
{
int n = 1000;
for (int i = 0; i < n; ++i)
{
var timeout1 = new CancellationTokenSource(2100);
await FirstThingAsync(timeout1.Token);
var timeout2 = new CancellationTokenSource(2200);
await SecondThingAsync(timeout2.Token);
var timeout2 = new CancellationTokenSource(2300);
await ThirdThingAsync(timeout3.Token);
}
}
The code above will raise an exception if any task exceeds its timeout, which may not be exactly what you want. You can catch the OperationCanceledException if you wish to handle this differently.
Task<string> RunList(int client)
{
return pages[client];
}
private async void Form1_DoubleClick(object sender, EventArgs e)
{
for (int x = 0; x < listBox1.Items.Count; x++)
{
RunList(x);
}
}
This will fly through the loop of tasks, but how do you know when the results are all in without compromising speed of the loop?
You can await on the result of WhenAll to ensure that all of the tasks have completed at that point in code. (It's important not to use WaitAll here, that would block the UI thread.)
private async void Form1_DoubleClick(object sender, EventArgs e)
{
var tasks = new List<Task<string>>();
for (int x = 0; x < listBox1.Items.Count; x++)
{
tasks.Add(RunList(x));
}
await Task.WhenAll(tasks);
}
The basic idea here is to simply start the tasks before calling await on them. Here is a simpler example with just two Tasks:
await Task.Delay(1000);
await Task.Delay(1000);
This will perform the first task and then the second task.
var task1 = Task.Delay(1000);
var task2 = Task.Delay(1000);
await task1;
await task2;
This will start both tasks and then continue on after both tasks have finished, allowing then to run concurrently.