Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I cant seem to find the information that im looking for in the documentation and could use a second pair of eyes. I would like to do this without testing; only a visual examination and theory discussion.
My draft attempt sets a bool which will only allow an async method to be run if the returned task sets its value to Task.IsCompleted. My question is, will this code do what I assume it will and if not, what is an alternative that will perform only a single call at a time? (assuming the infinite loop and async task remain unchanged)
You may fairly assume that RunAsync() is an asynchronous method, denoted by the async keyword, containing an awaitable task which returns a Task instance.
bool asyncOutputCallAllowed = true;
while (true)
{
if (asyncOutputCallAllowed)
{
asyncOutputCallAllowed = false;
asyncOutputCallAllowed = RunAsync().IsCompleted;
}
}
I am guessing that you are trying to do the following: make an async call, keep looping and doing other stuff while also waiting for async-task to finish, and then start a new async task when the previous one finishes. If so, then you probably want something along the following lines:
Task activeOperation = null;
while (true)
{
if (activeOperation == null)
{
// No async operation in progress. Start a new one.
activeOperation = RunAsync();
}
else if (activeOperation.IsCompleted)
{
// Do something with the result.
// Clear active operation so that we get a new one
// in the next iteration.
activeOperation = null;
}
// Do some other stuff
}
Depending on your exact algorithm, you might want to start the new task in the same iteration in which the previous one finishes. That is just a small tweak of the above.
If you are not doing anything else in the loop except wait for the async-task, then you can get rid of the loop entirely and use a continuation instead (see ContinueWith).
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 days ago.
Improve this question
I currently am running the following code:
async Task Method()
{
foreach (DataGridViewRow row in dataGridView1.Row)
{
// Do Something
}
await Task.Delay(120000);
}
However this obviously does only wait for a certain time. Now I am wondering how to change it, so that it will wait until one iteration inside the foreach loop is completely independent of time to then start another iteration until the loop/loops are completed.
I have read about Task.WhenAll() but I don't get it. I could also put my Method() in a foreach loop if it is required or preferred.
If the code inside the loop is synchronous, then the statements inside of the loop will complete before you get to your awaited delay. If you have asynchronous statements inside of the loop then you want to await those to ensure they complete before processing the next line.
If you want to ensure that your "Method" finish completes before it is called again, you want to ensure that the call to Method() is awaited or otherwise Waited.
You don't normally add things like Task.Delay in code to force it to delay until other code has executed. That would be used for testing out waiting behaviour. Code should take only as long as it needs to, and when it comes to asynchronous code, as long as it is awaited properly, there is no need to put in things like delays.
Asynchronous code allows your code, or processes around your code to manage a degree of parallelism. It is not a silver bullet to solve problems like "my code is taking too long", and you do need to be very careful with parallelism when it comes to references to classes that are not thread safe. (I.e. EF DbContexts)
To avoid confusion, you should also always suffix your async methods with "Async" to make it crystal clear they are asynchronous and should be awaited. I.e. public Task MethodAsync().
So in summary,
Remove Task.Delay().
If your loop makes calls to async calls, await them. Synchronous calls will be done sequentially so the loop will already wait for them to complete.
Ensure that if the caller of MethodAsync is async itself, the call to MethodAsync should be awaited. If the caller of MethodAsync is synchronous and you cannot use await, then Wait the returned Task. Just don't, this is a rabbit hole you don't want to look down, make a synchronous version of the code.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
My first non-async attempt was to use a timer to call the process every 15 seconds. This quickly created multiple processes running which started a race condition on the database because the function _myApp.ProcessQueue(); could take 5-10 minutes to run based on the size of the queue. This actually locked up the database because it was trying to read and write to the same rows. If I increase the timer it would prevent the potential for a race condition but I don't think that's a very pragmatic way to go about this service.
protected override void OnStart(string[] args)
{
_log.Info($"Service is started at {DateTime.Now}.");
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 15000;
timer.Enabled = true;
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
int recCount = _dbHandler.CheckQueueCount();
if (recCount > 0)
{
_log.Info($"Found {recCount} records in the queue.");
try
{
_myApp.ProcessQueue();
}
catch (Exception exception)
{
_log.Error(exception);
Stop();
}
}
}
I'm thinking the way to go about this is to use an asynchronous function but I'm having trouble getting that written since I haven't used .Net's async capabilities before.
Use the OnStart() to initialize your runner in an other thread (Task.Run() or if you have to tune some parameters Task.Factory.Start()) to have a proper return of the method within short time.
If I understand you correctly, you only want to process one job at a time and after that you want to process the next one, right?
My examples include always to wait for additional 15s. If you don't want this, you have to adjust the code a little bit.
Without async/await
To synchronize your loop with your job processing, you can start the job in another thread (see above) and use a AutoResetEvent. In your loop you gonna wait with _autoResetEvent.WaitOne() and as soon as your job has been done you can signal with _autoResetEvent.Set() the other thread to continue.
Use something appropriate to wait for the 15s like Thread.Sleep()
With async/await
It's much easier, you only have to await your task call.
await Task.Run(() => MyJobMethod(argA, argB, ...));
await Task.Delay(15000);
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
An asynchronous method like below should be executed without waiting in a ASP.NET MVC website.
public async Task DoStaff()
{
// business logic here
}
And we found two solutions to accomplish this and both work on our testbed:
Solution 1:
public void DoStaffWrapper()
{
DoStaff();
// clean up
}
public ActionResult Caller()
{
DoStaffWrapper();
// return blah blah blah;
}
Solution 2:
public async Task DoStaffWrapperAsync()
{
await DoStaff();
// clean up
}
public ActionResult Caller()
{
Task.Run(() => DoStaffWrapperAsync());
// return blah blah blah;
}
So what is the difference between them? which is the better and why? Any benefits?
Unless you have precise control over the lifecycle of your IIS pool (or unless you're not actually running on IIS), you should use QueueBackgroundWorkItem to launch your fire-and-forget tasks. It makes sure the runtime is able to track them, and won't terminate prematurely the process.
HostingEnvironment.QueueBackgroundWorkItem(_ => DoStaff());
If for some reason you don't want to use this method, or don't need it, there's an important difference between the two ways of calling the async method:
DoStaff() will run synchronously on the current thread until an await statement is found, then it will yield control over the thread (and whatever you have after DoStaff will be able to execute. Also, the mehtod will execute inside of ASP.NET's synchronization context, so you will run into trouble if you're not using .ConfigureAwait(false) whenever awaiting calls inside of it.
Task.Run(() => DoStaffWrapperAsync()) will entirely run asynchronously, and in a separate context (so you won't run into the aforementioned issue).
To put it simple, take the following method:
public Task DoStaff()
{
Thread.Sleep(1000);
await AnotherMethodAsync();
Thread.Sleep(1000);
}
If you call DoStaff, the call will be blocking for one second. If you call Task.Run(() => DoStaff()), the call will return immediately. But if there's no significant amount of work before the first await, then you'll be jumping to a new thread for no practical gain.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
private async void btnLoadFile_Click(object sender, EventArgs e)
{
if(AccountsFile.ShowDialog()==DialogResult.OK)
{
Accounts = File.ReadAllLines(AccountsFile.FileName);
foreach(string str in Accounts)
{
await LoadAccount(str);
}
}
}
I've ran into a problem, I know how Asynchronous programming works it will wait for the task to be complete but LoadAccount() will never complete because it calls a function with a never ending while loop so it will not reach the next string in Accounts.
I don't know where to start with this problem. Any solutions?
Instead of waiting for each account successively, you could wait for them collectively. This way, even if one of your accounts enters an infinite loop, the others could still proceed to load.
Accounts = File.ReadAllLines(AccountsFile.FileName);
Task completionTask = Task.WhenAll(Accounts.Select(LoadAccount));
You would typically want to store completionTask in a class variable. Subsequently, when you break out of the indefinite while loop within your LoadAccount calls (for example, by signalling cancellation via a polled CancellationToken), you can use this completionTask to wait for all your tasks to complete.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I've got an activity that I need to run on a background thread in a C#/XAML app, so I'm doing this:
Task.Factory.StartNew(() => ImportFile());
I'm returning the Task value to another bit of code that then needs to take action after the thread-based work has completed. The code looks like this:
Action<Task> finalise = async delegate { await FinishImport(dbList); };
dbList.ImportFileAsync().ContinueWith(finalise);
When I run the code, however, debugging statements in FinishImport are being executed before the background thread has finished.
What am I misunderstanding here? I thought the whole point of ContinueWith was that it would execute the continuation code after the target task completes.
You should use Task.Run rather than Task.Factory.StartNew in async code. Task.Run understands async methods while StartNew will return a Task representing only the beginning of that async method.
As a side note, it's usually best to not have Task.Run hidden inside a library method.
Also, it's far easier to use await than ContinueWith. And async methods should end with "Async".
So, applying these guidelines makes your code look like:
await Task.Run(() => dbList.ImportFileAsync());
await FinishImportAsync(dbList);
what ImportFileAsync() does?
finalise will run after the thread of ImportFileAsync() will end
if
ImportFileAsync(){ Task.Factory.StartNew(() => ImportFile());}
then ImportFileAsync will call a new thread for ImportFile() and then exit it won't wait for ImportFile()
to finish
you wanna do
Task.Factory.StartNew(() => dbList.ImportFile()).ContinueWith(finalise);