I have used Task.WaitAll inside an async method in my HomeController, but it is not waiting to complete execution of the async methods. What did I do wrong here? Instead of waiting, it immediately goes to the next statement.
HomeController.cs:
private List<Task> taskList = new List<Task>();
public ActionResult Index()
{
for (i=0; i<5; i++)
{
SendMessages();
}
Task.WaitAll(taskList.ToArray());
// call demo method
}
private async Task SendMessages()
{
var task = Task.Factory.StartNew(() => ProcessMessages()
taskList.Add(task);
}
private async Task ProcessMessages()
{
while (run for 10 minutes)
{
// data save
}
}
I have added a Task into taskList and used Task.WaitAll(taskList.ToArray()); to wait for all tasks to complete, then call demo method. But instead of waiting and executing the whole loop, it immediately goes down after Task.WaitAll(taskList.ToArray()); and executes call demo method. Why is this?
Task.Factory.StartNew should not be used to launch asynchronous operations, since it does not unwrap the returned Task, and instead returns a new Task that completes as soon as the asynchronous operation launches (or, more precisely, completes its synchronous part). You should use Task.Run instead.
Additionally, SendMessages should not be async. However, Index should be, allowing you to use the asynchronous WhenAll instead of the blocking WaitAll.
private List<Task> taskList = new List<Task>();
public async Task<ActionResult> Index()
{
for (i = 0; i < 5; i++)
{
SendMessages();
}
await Task.WhenAll(taskList);
// call demo method
}
private void SendMessages()
{
var task = Task.Run(() => ProcessMessagesAsync()); // here
taskList.Add(task);
}
private async Task ProcessMessagesAsync()
{
while (run for 10 minutes)
{
// data save
}
}
Related
Im trying to perform a synchronization task without blocking UI thread. I have implemented a Android Service to do so, but I found out, if the synchronization task needs too much computational time, the UI thread was blocked. So I tried the migration to IntentService. This is how my IntentService looks like:
[Service]
public class SynchronizeIntentService : IntentService
{
static readonly string TAG = typeof(SynchronizeIntentService).FullName;
private NotificationCompat.Builder Builder;
private NotificationManagerCompat NotificationManager;
public SynchronizeIntentService() : base("SynchronizeIntentService")
{
}
public override void OnDestroy()
{
var tmp = 5;
base.OnDestroy();
}
private NotificationChannel createNotificationChannel()
{
var channelId = Constants.NOTIFICATION_CHANNELID;
var channelName = "My Notification Service";
var Channel = new NotificationChannel(channelId, channelName, Android.App.NotificationImportance.Default);
Channel.LightColor = Android.Resource.Color.HoloBlueBright;
Channel.LockscreenVisibility = NotificationVisibility.Public;
return Channel;
}
private void createForegroundService()
{
var mNotificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
mNotificationManager.CreateNotificationChannel(createNotificationChannel());
}
var notificationBuilder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNELID);
GenerateNotification();
StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, Builder.Notification);
}
private void GenerateNotification()
{
NotificationManager = NotificationManagerCompat.From(this);
Builder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNELID);
Builder.SetContentTitle(ContaScan.Classes.Localize.GetString("Global_SynchProcess", ""))
.SetSmallIcon(Resource.Drawable.icon)
.SetPriority(NotificationCompat.PriorityLow);
}
protected async override void OnHandleIntent(Intent intent)
{
Log.Debug(TAG, "Service Started!");
await Synch();
Log.Debug(TAG, "Service Stopping!");
StopForeground(true);
this.StopSelf();
}
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
base.OnStartCommand(intent, flags, startId);
createForegroundService();
return StartCommandResult.Sticky;
}
private async Task Synch()
{
//Large synch process
}
}
And this is how the service is getting started:
startServiceIntent = new Intent(Android.App.Application.Context, typeof(SynchronizeIntentService));
startServiceIntent.SetAction(Constants.ACTION_START_SERVICE);
ContextWrapper contextWrapper = new ContextWrapper(Android.App.Application.Context);
contextWrapper.StartService(startServiceIntent);
The problem is OnDestroy() method is called while the Synch() task is being performed and looks like the IntentService is being killed before ending the process.
What am I doing wrong?
First, check your API level. This class was deprecated in API level 30.
And then, when you use the OnHandleIntent, do not call Service.stopSelf().
This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call Service.stopSelf().
For more details, please check the link below. https://developer.android.com/reference/android/app/IntentService#onHandleIntent(android.content.Intent)
If there are two different reminders on the same grain activation to be fired at the same point, given that grain execution context is single-threaded, will both reminders be executed and interleaved at the same time?
Also, is the reminder execution limited by the default 30s timeout ?
Reminders are invoked using regular grain method calls: the IRemindable interface is a regular grain interface. IRemindable.ReceiveReminder(...) is not marked as [AlwaysInterleave], so it will only be interleaved if your grain class is marked as [Reentrant].
In short: no, reminder calls are not interleaved by default.
Reminders do not override the SiloMessagingOptions.ResponseTimeout value, so the default execution time will be 30s.
If you have a reminder that might need a very long time to execute, you can follow a pattern of starting the long-running work in a background task and ensuring that it is still running (not completed or faulted) whenever the relevant reminder fires.
Here is an example of using that pattern:
public class MyGrain : Grain, IMyGrain
{
private readonly CancellationTokenSource _deactivating = new CancellationTokenSource();
private Task _processQueueTask;
private IGrainReminder _reminder = null;
public Task ReceiveReminder(string reminderName, TickStatus status)
{
// Ensure that the reminder task is running.
if (_processQueueTask is null || _processQueueTask.IsCompleted)
{
if (_processQueueTask?.Exception is Exception exception)
{
// Log that an error occurred.
}
_processQueueTask = DoLongRunningWork();
_processQueueTask.Ignore();
}
return Task.CompletedTask;
}
public override async Task OnActivateAsync()
{
if (_reminder != null)
{
return;
}
_reminder = await RegisterOrUpdateReminder(
"long-running-work",
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1)
);
}
public override async Task OnDeactivateAsync()
{
_deactivating.Cancel(throwOnFirstException: false);
Task processQueueTask = _processQueueTask;
if (processQueueTask != null)
{
// Optionally add some max deactivation timeout here to stop waiting after (eg) 45 seconds
await processQueueTask;
}
}
public async Task StopAsync()
{
if (_reminder == null)
{
return;
}
await UnregisterReminder(_reminder);
_reminder = null;
}
private async Task DoLongRunningWork()
{
// Log that we are starting the long-running work
while (!_deactivating.IsCancellationRequested)
{
try
{
// Do long-running work
}
catch (Exception exception)
{
// Log exception. Potentially wait before retrying loop, since it seems like GetMessageAsync may have failed for us to end up here.
}
}
}
}
I'm making a Flutter app that using asynchronous a lot but it not working like how I understand about it. So I have some question about async and await in dart. Here is an example:
Future<int> someFunction() async {
int count = 0;
for (int i=0; i< 1000000000;i ++) {
count+= i;
}
print("done");
return count;
}
Future<void> test2() async {
print("begin");
var a = await someFunction();
print('end');
}
void _incrementCounter() {
print("above");
test2();
print("below");
}
test2() function will take a lot of time to done. right? So what i want is when test2 keep his work running until done, everything will keep running and not wait for test2().
When i run the function _incrementCounter(), it show the result:
above begin done below end
The problem is it didn't show "below" right away but it wait until someFunction() done.
This is result i want:
above begin below done end
This is the expected behavior since this change in Dart 2.0 which can be found in the changelog:
(Breaking) Functions marked async now run synchronously until the first await statement. Previously, they would return to the event loop once at the top of the function body before any code runs (issue 30345).
Before I give the solution I want to note you that async code are not running in another thread so the concept of:
keep his work running until done, everything will keep running and not
wait for test2()
Is fine but at some point your application are going to wait for test2() to finish since it is spawned as a task on the job queue where it will not leave other jobs to run before it is done. If you want the experience of no slowdown you want to either split the job into multiple smaller jobs or spawn an isolate (which are running in another thread) to run the calculation and later return the result.
Here is the solution go get your example to work:
Future<int> someFunction() async {
int count = 0;
for (int i=0; i< 1000000000;i ++) {
count+= i;
}
print("done");
return count;
}
Future<void> test2() async {
print("begin");
var a = await Future.microtask(someFunction);
print('end');
}
void _incrementCounter() {
print("above");
test2();
print("below");
}
main() {
_incrementCounter();
}
By using the Future.microtask constructor we are scheduling the someFunction() to be running as another task. This makes it so the "await" are going to wait since it will be the first true instance of an async call.
I have successfully been able to get the following nested async unit test working using TouchRunner (NUnitLite) in Xamarin:
[Test]
[Timeout (Int32.MaxValue)]
public async void NestedAsyncFail()
{
await Task.Run(async() =>
{
await Task.Delay(1000);
});
Assert.AreEqual(1, 0);
}
[Test]
[Timeout (Int32.MaxValue)]
public async void NestedAsyncSuccess()
{
await Task.Run(async() =>
{
await Task.Delay(1000);
});
Assert.AreEqual(1, 1);
}
Results: http://i.stack.imgur.com/5oC11.png
However, what if I want to test an async method that needs to perform some logic but also make some UI changes and thus, be executed on the main thread? Below is my attempt at doing this however, there are some issues...
[Test]
[Timeout (Int32.MaxValue)]
public void TestWithUIOperations()
{
bool result = false;
NSObject invoker = new NSObject ();
invoker.InvokeOnMainThread (async () => {
await SomeController.PerformUIOperationsAsync ();
result = true;
});
Assert.True (result);
}
With the Timeout attribute the TouchRunner freezes probably due to some thread locking. Without the Timeout attribute, the assertion returns false - I believe this is due to the async method not awaiting properly?
Can anyone advise where I'm going wrong and/or how this can be accomplished?
My use of the Timeout attribute in the first test is explained here:
https://bugzilla.xamarin.com/show_bug.cgi?id=15104
I've used an AutoResetEvent in situations like these to test our asynchronous startup routines:
[Test]
public void CanExecuteAsyncTest()
{
AutoResetEvent resetEvent = new AutoResetEvent(false);
WaitHandle[] handles = new WaitHandle[] { resetEvent};
bool success = false;
Thread t = new Thread(() => {
Thread.Sleep(1000);
success = true;
resetEvent.Set();
});
t.Start ();
WaitHandle.WaitAll(handles);
Assert.Equal(true, success);
}
If you're testing UI functionality, you may be better using Calabash or a related framework that is dedicated to testing UI flow.
I searched for some answer to my question on this site; but failed on every turn. I can delete fine if I don't put this in a ExecutorService, but if I do, it doesn't delete. No error occurs just the records are still in the database. Please advise.
public void deleteAllTrials(List<Trials>list) {
threadList = list;
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(new Job1());
executor.shutdown();
}
public class Job1 implements Runnable {
#Override
public void run() {
//Session session = (Session) entityManager.getDelegate();
EntityManagerFactory emf = entityManager.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
System.out.println("Size of threadList" + threadList.size());
long start = System.currentTimeMillis();
for(int i =0; i<threadList.size(); i++){
System.out.println("In thread...");
Trials mergedEntity = em.merge(threadList.get(i));
em.remove(mergedEntity);
}
//System.out.println("Result list in service:" + list.size());
//em.close();
long end = System.currentTimeMillis();
System.out.println("Threads took this long:" + (end - start));
}
}
I found out that EJBs are more powerful than I thought. If you just add #Asynchronus on top of the method you want the application to separate in a backing thread, it will be acting as a separate thread allowing the user to continue doing what he wants to do without waiting on the process to finish.
#Asynchronous
public void deleteAllTrials(List<TrialBillet>list) {
List<TrialBillet> threadList = new ArrayList<TrialBillet>();
threadList = list;
for(int i =0; i<threadList.size(); i++){
this.delete(threadList.get(i));
}
}
If you want to go with Executors, java-ee-7 has introduced ManagedExecutorService
From Java EE 7 tutorial
ManagedExecutorService: A managed executor service is used by
applications to execute submitted tasks asynchronously. Tasks are
executed on threads that are started and managed by the container. The
context of the container is propagated to the thread executing the
task. For example, by using an ManagedExecutorService.submit() call, a
task, such as the GenerateReportTask, could be submitted to execute at
a later time and then, by using the Future object callback, retrieve
the result when it becomes available.
code sample:
public class MyClass {
#Resource
private ManagedExecutorService mes;
public void myMethod() {
mes.execute(new Worker());
}
}