I'm trying to use async click event:
private async void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " click_begin");
await changeProgressBarAsync(ProgresBar_mainLoad);
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " click_end");
}
public Task changeProgressBarAsync(ProgressBar pb)
{
return Task.Factory.StartNew(() =>
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " task");
int count = 100;
while (count-- > 0)
{
pb.Dispatcher.Invoke(() =>
{
pb.Value += 1;
});
Thread.Sleep(10);
}
});
}
Following the async-await C# logic, lines
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " task");
and
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " click_end");
should show equal thread Id,
but this program show me
1 click_begin
5 task
1 click_end
So why it happens?
I did same test in console app
static void Main(string[] args)
{
TestClick();
Console.ReadKey();
}
public static async void TestClick()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is TestClick1");
await Worker();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is TestClick2");
}
public static Task Worker()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " it is Task");
});
}
And it show me
1 it is TestClick1
3 it is Task
3 it is TestClick2
You're explicitly starting a new task using Task.Factory.StartNew(). That's almost always going to run in a non-UI thread.
The async/await way of doing this is not to start a new task on a different thread, not to use the dispatcher, and not to use Thread.Sleep, but Task.Delay instead. Then you'd have:
public async Task ChangeProgressBarAsync(ProgressBar pb)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " task");
int count = 100;
while (count-- > 0)
{
pb.Value++;
await Task.Delay(10);
}
}
No extra threads anywhere.
In your console app you're seeing different threads because a console app doesn't have a synchronization context - there's nothing to make the continuation execute in the same thread as the thread that originally awaited.
Related
im new to C# and i was trying to figure out async and await . for practice i was trying to start method 1 in which method 2 is called twice . method 2 takes a value and increases it by 1 each 200 ms . instead of running method 2 the program ends after the first line of method 1 .
static void Main(string[] args)
{
Method1();
}
static int Method2(int x)
{
for (int i = 0; i < 10; i++)
{
x += 1;
Console.WriteLine(x);
Thread.Sleep(200);
}
Console.WriteLine("final" + " " + x + " " + Thread.CurrentThread.ManagedThreadId);
return x;
}
static async Task Method1()
{
Console.WriteLine("1 running");
int result1 = await Task.Run(() => Method2(0));
int result2 = await Task.Run(() => Method2(result1));
Thread.Sleep(1000);
Console.WriteLine("result " + result2 * 2);
}
what am i doing wrong here ?
When calling Method() you aren't waiting on it. It returns a task object that is not acted upon, and then Main() dutifully returns, which ends the program.
You can do this in Main():
public static void Main() {
Method1().GetAwaiter().GetResult();
}
Or use async Main() instead:
public static async Task Main() {
await Method1();
}
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 am trying to see how CPU is being utilized when I spawn a lot of tasks using the following code:
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Console.WriteLine("Main Started");
MainChild(sw).Wait();
Console.WriteLine("Main ended: "+sw.Elapsed);
}
static async Task MainChild(Stopwatch sw)
{
Task[] tasks = new Task[100];
for (int i = 0; i < 100; i++)
{
tasks[i] = Task.Factory.StartNew(new Action(async()=> {
await Task.Delay(1000);
Console.WriteLine("Task1 completed: " + sw.Elapsed);
}));
}
await Task.WhenAll(tasks);
}
I noticed that the main thread executes the :"Main Ended: " even before the tasks are executed. Why is this?
The Task.Factory.StartNew method is outdated and almost never used this days, also it doesn't understand async delegates.
Another thing is that the Action delegate returns void and async void is a fire-and-forget type of action. This operation doesn't return Task and is not awaited.
Change Action:
tasks[i] = Task.Factory.StartNew(new Action(async () =>
{
await Task.Delay(1000);
Console.WriteLine("Task1 completed: " + sw.Elapsed);
}));
To Func<Task> and Task.Run:
tasks[i] = Task.Run(new Func<Task>(async () =>
{
await Task.Delay(1000);
Console.WriteLine("Task1 completed: " + sw.Elapsed);
}));
As delegate type is inferred by compiler we can shorten it to:
tasks[i] = Task.Run(async () => ...
Now it is working as expected and waits for all tasks to finish execution
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);
}
I'm trying to find a way of causing the program to not pause but for their to be a delay to execute certain tasks. I.e. I am trying to delay outputting 'Hello' to the console for 10 seconds for example, but the program will continue to execute the rest of the program.
Using TPL:
static void Main(string[] args)
{
Console.WriteLine("Starting at " + DateTime.Now.ToString());
Task.Run(() =>
{
Thread.Sleep(10000);
Console.WriteLine("Done sleeping " + DateTime.Now.ToString());
});
Console.WriteLine("Press any Key...");
Console.ReadKey();
}
output:
Starting at 2/14/2017 3:05:09 PM
Press any Key...
Done sleeping 2/14/2017 3:05:19 PM
just note that if you press a key before 10 seconds, it will exit.
There are 2 typical ways to simulate a delay:
an asynchronous task-like: Task.Delay
or a blocking activity: Thread.Sleep
You seem to refer to the first situation.
Here it is an example
public static void Main(string[] args)
{
Both();
}
static void Both() {
var list = new Task [2];
list[0] = PauseAndWrite();
list[1] = WriteMore();
Task.WaitAll(list);
}
static async Task PauseAndWrite() {
await Task.Delay(2000);
Console.WriteLine("A !");
}
static async Task WriteMore() {
for(int i = 0; i<5; i++) {
await Task.Delay(500);
Console.WriteLine("B - " + i);
}
}
Output
B - 0
B - 1
B - 2
A !
B - 3
B - 4
Start a new thread:
Task.Factory.StartNew(new Action(() =>
{
Thread.Sleep(1000 * 10); // sleep for 10 seconds
Console.Write("Whatever");
}));
You could use a combination of Task.Delay and ContinueWith methods:
Task.Delay(10000).ContinueWith(_ => Console.WriteLine("Done"));
You could use 'Thread.Sleep(10000);'
See:
https://msdn.microsoft.com/en-us/library/d00bd51t(v=vs.110).aspx