I'm trying to use Async and Await for upload process. I created a small code to see if it works.
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
TestAsync().Wait();
}
}
public static async Task TestAsync()
{
await Task.Run(() => {
Thread.Sleep(1000);
var context = new CommonEntities();
context.AddToDummies(new Dummy { TimeStamp = DateTime.Now, Caption = "Async" });
context.SaveChanges();
});
}
}
But for some reason, it never gets to Console.WriteLine. If I replaced var context = new EntityObject(); with var stringBuilder = new StringBuilder(); then it worked.
The idea is that I will create a method which has many complex procedures of saving and updating database as well as calling a webservice and store the result to database etc. Let say that method is called MethodA.
public static async void test()
{
await Task.Run(() => MethodA());
}
But before going further, I am stuck in this simple test. Any idea why that is?
You shouldn't be using async void anywhere other than an event handler.
async void doesn't allow the caller to wait (asynchronously or otherwise) for the operation to complete, it just moves on. In your case it reaches the end of Main and the application ends before you get a chance to reach the Console.WriteLine.
You need to change TestAsync to return a Task and wait for it in Main:
static void Main()
{
TestAsync().Wait();
}
public static async Task TestAsync()
{
await Task.Run(() =>
{
var objectContext = new CommonEntities();
Console.WriteLine("Processed");
});
}
Related
How to call on async Task function from Void class?
Let's say I got this built up like this,
I Want to call the methods in Run() in sync, but in the DoSomeStuffAsync and DoSomeStuffAsync 2
It requires await on some functions that has async awaitable functions.
My Question is, how can I in DoTask1 e.g. make the task to run sync? Like now the tasks just starts it and it doesn't wait until it finish at all.
static void Main(string[] args)
{
Run();
}
public void Run()
{
DoTask1();
DoTask2();
}
public void DoTask1()
{
var tasks = Task.Run(async () =>
{
await DoSomeStuffAsync();
await DoSomeStuffAsync2();
});
Task.WaitAll(tasks);
}
public void DoTask2()
{
var tasks = Task.Run(async () =>
{
await DoSomeStuffAsync();
await DoSomeStuffAsync2();
});
Task.WaitAll(tasks);
}
private async Task DoSomeStuffAsync(int daysBack)
{
try
{
var data= await GetData();
var objj = GenerateObjects();
await InsertToDb(objj ));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private async Task DoSomeStuffAsync2(int daysBack)
{
try
{
var data= await GetOtherData();
var objj = GenerateObjects();
await InsertToDb(objj ));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The Console app static void Main() is calling on the Run() function.
You have a couple of options. For both of the options below, you should first make your Run method properly asynchronous (i.e., async Task).
If this is a .NET Core project, then option A is to make Main an async Task method. Then you can use async all the way.
If not, then you can have a single blocking call. I recommend that this go into your Main method, as such:
static void Main()
{
Run().GetAwaiter().GetResult();
}
Async void is a bad choice, generates compiler warnings, if an exception is uncaught there, your application is dead and you won’t probably have a proper call stack to debug with. But if you want, you already have the solution just
call directly the async task method. And wrappe it in a exception catcher
static void Main(string[] args)
{
Task callTask = Task.Run(() => Run());
callTask.Wait();
}
public async Task Run()
{
await DoSomeStuffAsync();
}
I'm creating a message processor to take messages of a queue
I have used topshelf for this and justgot some basic code for now. However my message processor is stuck in a loop and causing my topshelf service to not start. I thought if I returned and stored the task, this would not be the case
class Program
{
static void Main(string[] args)
{
HostFactory.Run(configure =>
{
configure.Service<WorkerService>(service =>
{
service.ConstructUsing(() => new WorkerService());
service.WhenStarted(s => s.Start());
service.WhenStopped(s => s.Stop());
});
configure.RunAsLocalSystem();
});
}
}
public class WorkerService
{
private Task _task;
private Processor _processor;
private readonly CancellationTokenSource _cancellation;
public WorkerService()
{
_cancellation = new CancellationTokenSource();
_processor = new Processor();
}
public void Start()
{
Console.WriteLine("Starting");
_task = _processor.Run(_cancellation.Token);
Console.WriteLine("I NEVER GET HERE");
}
public void Stop()
{
_cancellation.Cancel();
_task.Wait();
}
}
public class Processor
{
public async Task Run(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Running");
}
}
}
So when I look at my windows services I just see this app stuck in "Starting"
Your run function doesn't actually hit an await call (where it will exit and later resume). In fact, it doesn't exit at all. You're stuck in the Run method. Try putting this after your Console.WriteLine:
await Task.Delay(200);
In addition, you might consider not mixing async/await with traditional Task.Wait(), as that's known to cause deadlocks as well. Example: await vs Task.Wait - Deadlock?
I need to do a work in a Task (infinite loop for monitoring) but how can I get the result of this work?
My logic to do this stuff i wrong? This is a scope problem I think.
There is an example simplified:
The variable is "first" and I want "edit"
namespace my{
public class Program{
public static void Main(string[] args){
Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
Console.WriteLine(p.getVar());// result="first"
}
}
public class Logic{
public string test = "first";
public void process(){
while(true){
//If condition here
this.test = "edit";
}
}
public String getVar(){
return this.test;
}
}
}
It can be done using custom event. In your case it can be something like:
public event Action<string> OnValueChanged;
Then attach to it
p.OnValueChanged += (newValue) => Console.WriteLine(newValue);
And do not forget to fire it
this.test = "edit";
OnValueChanged?.Invoke(this.test);
Tasks aren't threads, they don't need a .Start call to start them. All examples and tutorials show the use of Task.Run or Task.StartNew for a reason - tasks are a promise that a function will execute at some point in the future and produce a result. They will run on threads pulled from a ThreadPool when a Task Scheduler decides they should. Creating cold tasks and calling .Start doesn't guarantee they will start, it simply makes the code a lot more difficult to read.
In the simplest case, polling eg a remote HTTP endpoint could be as simple as :
public static async Task Main()
{
var client=new HttpClient(serverUrl);
while(true)
{
var response=await client.GetAsync(relativeServiceUrl);
if(!response.IsSuccessStatusCode)
{
//That was an error, do something with it
}
await Task.Delay(1000);
}
}
There's no need to start a new Task because GetAsync is asynchronous. WCF and ADO.NET also provide asynchronous execution methods.
If there's no asynchronous method to call, or if we need to perform some heavey work before the async call, we can use Task.Run to start a method in parallel and await for it to finish:
public bool CheckThatService(string serviceUrl)
{
....
}
public static async Task Main()
{
var url="...";
//...
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
if(!ok)
{
//That was an error, do something with it
}
await Task.Delay(1000);
}
}
What if we want to test multiple systems in parallel? We can start multiple tasks in parallel, await all of them to complete and check their results:
public static async Task Main()
{
var urls=new[]{"...","..."};
//...
while(true)
{
var tasks=urls.Select(url=>Task.Run(()=>CheckThatService(url));
var responses=await Task.WhenAll(tasks);
foreach(var response in responses)
{
///Check the value, due something
}
await Task.Delay(1000);
}
}
Task.WhenAll returns an array with the results in the order the tasks were created. This allows checking the index to find the original URL. A better idea would be to return the result and url together, eg using tuples :
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
return (true,url);
}
The code wouldn't change a lot:
var tasks=urls.Select(url=>Task.Run(()=>CheckThatService(url));
var responses=await Task.WhenAll(tasks);
foreach(var response in responses.Where(resp=>!resp.ok))
{
///Check the value, due something
}
What if we wanted to store the results from all the calls? We can't use a List or Queue because they aren't thread safe. We can use a ConcurrentQueue instead:
ConcurrentQueue<string> _results=new ConcurrentQueue<string>();
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
_results.Enqueue(someresult);
return (true,url);
}
If we want to report progress regularly we can use IProgress<T> as shown in Enabling Progress and Cancellation in Async APIs.
We could put all the monitoring code in a separate method/class that accepts an IProgress< T> parameter with a progress object that can report success, error messages and the URL that caused them, eg :
class MonitorDTO
{
public string Url{get;set;}
public bool Success{get;set;}
public string Message{get;set;}
public MonitorDTO(string ulr,bool success,string msg)
{
//...
}
}
class MyMonitor
{
string[] _urls=url;
public MyMonitor(string[] urls)
{
_urls=url;
}
public Task Run(IProgress<MonitorDTO> progress)
{
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
if(!ok)
{
_progress.Report(new MonitorDTO(ok,url,"some message");
}
await Task.Delay(1000);
}
}
}
This class could be used in this way:
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
await monitor.Run(progress);
}
Enabling Progress and Cancellation in Async APIs shows how to use the CancellationTokenSource to implement another important part of a monitoring class - cancelling it. The monitoring method could check the status of a cancellation token periodically and stop monitoring when it's raised:
public Task Run(IProgress<MonitorDTO> progress,CancellationToken ct)
{
while(!ct.IsCancellationRequested)
{
//...
}
}
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
var cts = new CancellationTokenSource();
//Not awaiting yet!
var monitorTask=monitor.Run(progress,cts.Token);
//Keep running until the first keypress
Console.ReadKey();
//Cancel and wait for the monitoring class to gracefully stop
cts.Cancel();
await monitorTask;
In this case the loop will exit when the CancellationToken is raised. By not awaiting on MyMonitor.Run() we can keep working on the main thread until an event occurs that signals monitoring should stop.
The getVar method is executed before the process method.
Make sure that you wait until your task is finished before you call the getVar method.
Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
t.Wait(); // Add this line!
Console.WriteLine(p.getVar());
If you want to learn more about the Wait method, please check this link.
I have a console application in which I need to retrieve some data from 4 different sites. I placed each HTTP request in a task and I wait for them all to complete.
It was working when I only had to get data from 2 sites. but then I needed to add other sources of data and when adding 3 or more requests, the Task.WaitAll() hangs.
Below is my code.
The reason I ended up using Task.WaitAll() was because I need to stop and prevent the console application from exiting - i.e. I need to perform other tasks only after all the HTTP requests come back with data.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static Task[] tasks = new Task[3];
static void Main(string[] args)
{
try
{
Run();
}
catch (System.Exception ex)
{
}
}
public static async void Run()
{
//works when using one or two tasks
tasks[0] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[1] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
//fails when add 3 or more task
tasks[2] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
//tasks[3] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
Task.WaitAll(tasks);
var result4 = ((Task<Stream>)tasks[2]).Result;
}
}
public static class HttpExtensions
{
public static Stopwatch sw;
public static long http_ticks = 0;
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request)
{
var taskComplete = new TaskCompletionSource<HttpWebResponse>();
request.BeginGetResponse(asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
}, request);
return taskComplete.Task;
}
public static async Task<Stream> GetMyData(string urlToCall)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToCall);
request.Method = HttpMethod.Get;
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
//using (var sr = new StreamReader(response.GetResponseStream()))
//{
return response.GetResponseStream();
//}
}
}
public static class HttpMethod
{
public static string Head { get { return "HEAD"; } }
public static string Post { get { return "POST"; } }
public static string Put { get { return "PUT"; } }
public static string Get { get { return "GET"; } }
public static string Delete { get { return "DELETE"; } }
public static string Trace { get { return "TRACE"; } }
public static string Options { get { return "OPTIONS"; } }
public static string Connect { get { return "CONNECT"; } }
public static string Patch { get { return "PATCH"; } }
}
}
There a number of concerns.
First, as I mentioned in the comments above, by not returning a Task you are more or less hanging your application since it can't tell when the Task is completed.
However, once you change the Run() method to return a task, you need to invoke it via a Task.Run call in your Main method.
Second, you are over-complicating your code by using WebClient. Switch to HttpClient and take advantage of its natural async/await API.
Third, you aren't actually awaiting anything in your Run() method so changing it to a task does nothing since you aren't awaiting a result which will cause it to run synchronously (no pun intended). Update your method to await a result.
Finally, WaitAll blocks the thread, which may not be what you want. You can use WhenAll instead and await that call, allowing your application to release the thread while your tasks run.
Below is a complete, working example of my recommended modifications, simplified to show a working program. The Main method recommendation is taken from https://social.msdn.microsoft.com/Forums/vstudio/en-US/fe9acdfc-66cd-4b43-9460-a8053ca51885/using-new-asyncawait-in-console-app?forum=netfxbcl
class Program
{
static Task[] tasks = new Task[3];
static HttpClient _client = new HttpClient();
static void Main(string[] args)
{
Console.WriteLine("Main start");
Task t = Run();
t.ContinueWith((str) =>
{
Console.WriteLine(str.Status.ToString());
Console.WriteLine("Main end");
});
t.Wait();
}
public static async Task Run()
{
tasks[0] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[1] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[2] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
await Task.WhenAll(tasks);
var result4 = (await (Task<Stream>)tasks[2]);
}
public static async Task<Stream> GetMyData(string urlToCall)
{
return await _client.GetStreamAsync(urlToCall);
}
}
I think the issue is more of understanding Task and async await; and I may be wrong so apologies up front.
Task is a managed thread that goes into a thread pool. Task has a Task.Result of Type T.
You can create a Task and then Start it and then Wait it. (Never a good idea to start and then immediately wait a task but for understanding...)
var task = new Task(() => DoWork());
task.Start();
task.Wait();
The task will perform the DoWork() method in a new thread.
The calling thread will BLOCK at task.Wait();
You can also give a Task a ContinueWith Action that will perform the remaining work on the calling thread.
var task = new Task(() => DoWorkOnNewThread());
task.ContinueWith(() => MainThreadWork());
task.Start(); //Notice no more task.Wait();
So, if you're following that little bit then you can sort of use async await correctly.
The async keyword tells the compiler to wrap all remaing code AFTER reaching the await keyword WHERE A GetAwaiter() is returned. This is important because until you actually create a task (preferably started also) and return it then you have no GetAwaiter();
private Task DoWorkAsync()
{
var task = new Task(() => DoWork());
task.Start();
return task;
}
private async void Method()
{
//Main thread code...
await DoWorkAsync(); //Returns to whoever called Method()
//More main thread code to be QUEUED to run AFTER DoWorkAsync is complete.
//This portion of code, when compiled, is essentially wrapped in the ContinueWith(...
}
So if you're still following along then here's the kicker. You're on the same thread UNTIL you return a GetAwaiter() which is only found in a Task. If the Task has never started then you'll await that Task forever technically. So here's some comments showing the thread transitions.
private Task DoWorkAsync()
{
Debug.WriteLine("Still on main thread")
var task = new Task(() =>
{
Debug.WriteLine("On background thread");
});
task.Start(); //On main thread.
return task; //On main thread.
}
private async void Method()
{
Debug.WriteLine("On main thread");
await DoWorkAsync(); //returns to caller after DoWorkAsync returns Task
Debug.WriteLine("Back on main thread"); //Works here after the task DoWorkAsync returned is complete
}
An easier way to return the task running is to return Task.Run(() => DoWork()); If you look at the return value of Run it is Task and that task has already been started.
Forgive me if this isn't what you wanted but I felt like there is more of a confusion about using async await correctly than there is confusion about your code. I may be wrong but I felt that if you could understand more about the Task itself and how async await works you would see your issue. If this isn't what you're looking for I'll delete the answer.
After spending a very frustrating and unproductive day on this, I'm posting here in search of help.
I am using a third-party library that initiates a network connection in an unknown manner (I do know however it's a managed wrapper for an unmanaged lib). It lets you know about the status of the connection by invoking an event StatusChanged(status).
Since obviously invoking the network is costly and I may not need it for my Service, I inject an AsyncLazy<Connection> which is then invoked if necessary. The Service is accessed by ParallelForEachAsync which is an extension I made to process Tasks concurrently, based on this post.
If accessed sequentially, all is well. Any concurrency, even 2 parallel tasks will result in a deadlock 90% of the time. I know it's definitely related to how the third-party lib interacts with my code because a) I am not able to reproduce the effect using the same structure but without invoking it and b) the event StatusChanged(Connecting) is received fine, at which point I assume the network operation is started and I never get a callback for StatusChanged(Connected).
Here's a as-faithful-as-possible repro of the code structure which doesn't reproduce the deadlock unfortunately.
Any ideas on how to go about resolving this?
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async Task MainAsync(string[] args)
{
var lazy = new AsyncLazy<Connection>(() => ConnectionFactory.Create());
var service = new Service(lazy);
await Enumerable.Range(0, 100)
.ParallelForEachAsync(10, async i =>
{
await service.DoWork();
Console.WriteLine("did some work");
}, CancellationToken.None);
}
}
class ConnectionFactory
{
public static Task<Connection> Create()
{
var tcs = new TaskCompletionSource<Connection>();
var session = new Session();
session.Connected += (sender, args) =>
{
Console.WriteLine("connected");
tcs.SetResult(new Connection());
};
session.Connect();
return tcs.Task;
}
}
class Connection
{
public async Task DoSomethinElse()
{
await Task.Delay(1000);
}
}
class Session
{
public event EventHandler Connected;
public void Connect()
{
Console.WriteLine("Simulate network operation with unknown scheduling");
Task.Delay(100).Wait();
Connected(this, EventArgs.Empty);
}
}
class Service
{
private static Random r = new Random();
private readonly AsyncLazy<Connection> lazy;
public Service(AsyncLazy<Connection> lazy)
{
this.lazy = lazy;
}
public async Task DoWork()
{
Console.WriteLine("Trying to do some work, will connect");
await Task.Delay(r.Next(0, 100));
var connection = await lazy;
await connection.DoSomethinElse();
}
}
public static class AsyncExtensions
{
public static async Task<AsyncParallelLoopResult> ParallelForEachAsync<T>(
this IEnumerable<T> source,
int degreeOfParallelism,
Func<T, Task> body,
CancellationToken cancellationToken)
{
var partitions = Partitioner.Create(source).GetPartitions(degreeOfParallelism);
bool wasBroken = false;
var tasks =
from partition in partitions
select Task.Run(async () =>
{
using (partition)
{
while (partition.MoveNext())
{
if (cancellationToken.IsCancellationRequested)
{
Volatile.Write(ref wasBroken, true);
break;
}
await body(partition.Current);
}
}
});
await Task.WhenAll(tasks)
.ConfigureAwait(false);
return new AsyncParallelLoopResult(Volatile.Read(ref wasBroken));
}
}
public class AsyncParallelLoopResult
{
public bool IsCompleted { get; private set; }
internal AsyncParallelLoopResult(bool isCompleted)
{
IsCompleted = isCompleted;
}
}
EDIT
I think I understand why it's happening but not sure how to solve it. While the context is waiting for DoWork, DoWork is waiting for the lazy connection.
This ugly hack seems to solve it:
Connection WaitForConnection()
{
connectionLazy.Start();
var awaiter = connectionLazy.GetAwaiter();
while (!awaiter.IsCompleted)
Thread.Sleep(50);
return awaiter.GetResult();
}
Any more elegant solutions?
I suspect that the 3rd-party library is requiring some kind of STA pumping. This is fairly common with old-style asynchronous code.
I have a type AsyncContextThread that you can try, passing true to the constructor to enable manual STA pumping. AsyncContextThread is just like AsyncContext except it runs the context within a new thread (an STA thread in this case).
static void Main(string[] args)
{
using (var thread = new AsyncContextThread(true))
{
thread.Factory.Run(() => MainAsync(args)).Wait();
}
}
or
static void Main(string[] args)
{
AsyncContext.Run(() => async
{
using (var thread = new AsyncContextThread(true))
{
await thread.Factory.Run(() => MainAsync(args));
}
}
}
Note that AsyncContextThread will not work in all STA scenarios. I have run into issues when doing (some rather twisted) COM interop that required a true UI thread (WPF or WinForms thread); for some reason the STA pumping wasn't sufficient for those COM objects.