Question about Future execution order in Dart [duplicate] - dart

This question already has answers here:
Dart - make long running synchronous function asynchronous
(3 answers)
Closed 10 months ago.
Here is my code,
Future<int> test() {
print('Start test()');
for (var i = 1; i < 100000; i++) {
for (var j = 1; j < 100000; j++) {
var k = i * j;
}
}
print('After a long running task in test()');
return Future<int>.value(1);
}
void main() {
test().then((result) => print('Done with test()'));
print('Done with main().');
}
and here is the output,
Start test()
After a long running task in test()
Done with main().
Done with test()
my question is, shouldn't 'Done with main()' be printed before 'After a long running task in test()'?

Use Future.microtask() if you want skip task.
Example:
Future<int> test() {
print('Start test()');
for (var i = 1; i < 100000; i++) {
for (var j = 1; j < 100000; j++) {
var k = i * j;
}
}
print('After a long running task in test()');
return Future<int>.value(1);
}
void main() {
Future.microtask(test);
print('Done with main().');
}
Output:
Done with main().
Start test()
After a long runnin task in test()

Related

How to implement a fire and forget function in Dart

I have the following Dart program:
import 'package:pedantic/pedantic.dart';
Future someFunc() async {
for (var i = 0; i < 100; i++) {
print('Value of i in someFunc(): ' + i.toString());
}
}
Future someOtherFunc() async {
for (var i = 0; i < 100; i++) {
print('Value of i in someOtherFunc(): ' + i.toString());
}
}
Future<int> main() async {
unawaited(someFunc());
unawaited(someOtherFunc());
print('End of program...');
return 0;
}
When I execute this, the output is:
Value of i in someFunc(): 0
Value of i in someFunc(): 1
Value of i in someFunc(): 2
...
Value of i in someFunc(): 99
Value of i in someOtherFunc(): 0
Value of i in someOtherFunc(): 1
Value of i in someOtherFunc(): 2
...
Value of i in someOtherFunc(): 99
End of program...
It looks like everything was executed synchronously. I was expecting something like:
Value of i in someFunc(): 0
Value of i in someFunc(): 1
Value of i in someOtherFunc(): 0
Value of i in someFunc(): 3
End of program...
Value of i in someOtherFunc(): 1
(etc...)
How do I create an asynchronous "fire and forget" function/method in Dart?
The reason you're seeing this code execute synchronously is because asynchronous methods in Dart execute as if they're synchronous until the first await, at which point execution of that method is suspended until the await completes. If you were performing actual asynchronous work in your methods, you'd see interleaving execution like you expect.
For example, here's some slight modifications to your code that will roughly result in the behavior you expect:
import 'package:pedantic/pedantic.dart';
Future someFunc() async {
for (var i = 0; i < 100; i++) {
// Future.microtask is used to schedule work on the microtask queue,
// which forces this method to suspend execution and continue on to someOtherFunc.
// If you were doing some actual asynchronous work, you wouldn't need this.
await Future.microtask(() => print('Value of i in someFunc(): ' + i.toString()));
}
}
Future someOtherFunc() async {
for (var i = 0; i < 100; i++) {
await Future.microtask(() => print('Value of i in someOtherFunc(): ' + i.toString()));
}
}
Future<int> main() async {
unawaited(someFunc());
unawaited(someOtherFunc());
print('End of program...');
return 0;
}
I highly recommend reading up on the Dart event loop and microtask queue, which will give you a good understanding of how asynchrony works in Dart

Dart File.writeAsString() method does not write to file if await is not done immediately

I have the following Dart code that doesn't behave as I expected:
final File file = File("result.csv");
Future send(String message) async {
try {
await file.writeAsString(message + '\n',
mode: FileMode.append, flush: true);
} catch (e) {
print("Error: $e");
}
return await file.length();
}
main() async {
final futures = <Future>[];
for (int i = 0; i < 100; i++) {
futures.add(send("$i"));
}
for (int i = 0; i < 100; i++) {
print(await futures[i]);
}
}
I expected the file to be written as soon as each call to await futures[i] in the second loop returned. However this does not seem to be happening.
The file should contain one line for each index from 0 to 99. But it contains a line with 99 followed by an empty line. And the print calls in the second loop always print the same file length, 3.
The event loop seems to be somehow merging the calls and only actually executing the last call, even though I still get 100 different futures that I await in the second loop.
Why is this happening and how can I allow the futures to run without awaiting them immediately (I really need to await only later, when all of the calls to send have been made)?
With the loop:
for (int i = 0; i < 100; i++) {
futures.add(send("$i"));
}
multiple send are immediately invoked and each one concurrently open and write a string in the file: you have a race condition and at the ends it happens that only one message it is written to the file.
Use a list of functions that return a future
With a closure it is possible to implement a sequenzialized version for file access that avoid the race condition.
Instead of creating a list of futures, create a list of functions that returns a future:
The shared file resource is accessed sequentially if you call and await such functions in a loop:
import 'dart:io';
final File file = File("result.csv");
typedef Future SendFunction();
Future send(String message) async {
try {
await file.writeAsString(message + '\n',
mode: FileMode.append, flush: true);
} catch (e) {
print("Error: $e");
}
var l = await file.length();
return l;
}
main() async {
final futures = List<SendFunction>();
//final futures = <Future>[];
for (int i = 0; i < 100; i++) {
//futures.add(send("$i"));
futures.add(() => send("$i"));
}
for (int i = 0; i < 100; i++) {
print(await futures[i]());
//print(await futures[i]);
}
}
synchronized package
synchronized offers lock mechanism to prevent concurrent access to asynchronous code.
In this case it may be used to avoid concurrent access to result.csv file:
import 'dart:io';
import 'package:synchronized/synchronized.dart';
final File file = File("result.csv");
final lock = new Lock();
Future send(String message) async {
try {
await file.writeAsString(message + '\n',
mode: FileMode.append, flush: true);
} catch (e) {
print("Error: $e");
}
return await file.length();
}
main() async {
final futures = <Future>[];
for (int i = 0; i < 100; i++) {
futures.add(lock.synchronized(() => send("$i")));
}
for (int i = 0; i < 100; i++) {
print(await futures[i]);
}
}

add each dataLabel a function on mouseover/mouseout

I want to add each dataLabel a (just call it "highlightPoint()") function on a mouseover event. It works, if I add this function to a single point.
chartObj.series[0].data[1].dataLabel.on("mouseover", function () {
chartObj.series[0].data[1].setState('hover');
});
It doesn't work if I loop threw my data points. I guess the reference to each individual point is incorrect or something like that.
jsfiddle-link
After you have looped through both data sets, i = 2 and k = 1. So the mouse events are always trying to use i=2 and k=1 to access the data point, which of course is out of bounds. See this fiddle: http://jsfiddle.net/bLvfS/1/
for (var i = 0; i < chartObj.series.length; i++) {
for (var k = 0; k < chartObj.series[i].data.length; k++) {
var onmouseover = function(u, j) {
return function() {chartObj.series[u].data[j].setState('hover');};
}
var onmouseout = function(u, j) {
return function() {chartObj.series[u].data[j].setState();};
}
chartObj.series[i].data[k].dataLabel.on("mouseover", onmouseover(i,k));
chartObj.series[i].data[k].dataLabel.on("mouseout", onmouseout(i,k));
}
}
I've added functions that get passed the current i,k pair and return the actual function you want to run on the mouse events. Maybe someone has a better solution... but it seems to work.
Problem is with closures, see working fiddle: http://jsfiddle.net/Fusher/bLvfS/2/
for (var i = 0; i < chartObj.series.length; i++) {
for (var k = 0; k < chartObj.series[i].data.length; k++) {
(function(i,k){
chartObj.series[i].data[k].dataLabel.on("mouseover", function () {
chartObj.series[i].data[k].setState('hover');
});
chartObj.series[i].data[k].dataLabel.on("mouseout", function () {
chartObj.series[i].data[k].setState();
});
})(i,k);
}
}

Getting all the active jobs from Quartz.NET scheduler

How I can get all the active jobs scheduled in the Quartz.NET scheduler? I tried the GetCurrentlyExecutingJobs() but it is returning always 0.
That method doesn't seem to work.
The only solution I had found was to loop through all the jobs:
var groups = sched.JobGroupNames;
for (int i = 0; i < groups.Length; i++)
{
string[] names = sched.GetJobNames(groups[i]);
for (int j = 0; j < names.Length; j++)
{
var currentJob = sched.GetJobDetail(names[j], groups[i]);
}
}
When a job is found it means that it is still active.
If you set your job as durable, though, it will never be deleted if there are no associated trigger.
In that situation this code works better:
var groups = sched.JobGroupNames;
for (int i = 0; i < groups.Length; i++)
{
string[] names = sched.GetJobNames(groups[i]);
for (int j = 0; j < names.Length; j++)
{
var currentJob = sched.GetJobDetail(names[j], groups[i]);
if (sched.GetTriggersOfJob(names[j], groups[i]).Count() > 0)
{
// still scheduled.
}
}
}
UPDATE:
I did some debugging to see what happens with GetCurrentlyExecutingJobs().
As a matter of fact it returns the job being executed but the elements are remove from the collection as soon as the job is executed.
You can check the 2 functions JobToBeExecuted and JobWasExecuted in the QuartzScheduler class.
A simpler loop option would be to get all of the job keys and iterate over them. This implementation is for a minimal API example. It gets all JobKeys from the scheduler and then iterates over each on to get the details and execution schedule. More details available in this sample repo: QuartzScheduler. If a job doesn't have a schedule, or it's scheduled execution has completed and there are no future executions planned then the job will not be included in the list of returned jobs.
app.MapGet("/schedules", async (ISchedulerFactory sf) =>
{
var scheduler = await sf.GetScheduler();
var definedJobDetails = new List<JobDetailsDto>();
var jobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
foreach (var jobKey in jobKeys)
{
var jobDetail = await scheduler.GetJobDetail(jobKey);
var jobSchedule = await scheduler.GetTriggersOfJob(jobKey);
if (jobDetail != null && jobSchedule != null)
{
definedJobDetails.Add(new JobDetailsDto(
jobDetail.Key.Name,
jobDetail.Key.Group,
jobDetail.Description,
jobSchedule.First().GetPreviousFireTimeUtc(),
jobSchedule.First().GetNextFireTimeUtc())
);
}
}
return definedJobDetails;
})

Getting all the tasks scheduled in the Quartz.NET scheduler

How I can get all the tasks that has been scheduled to the Quartz scheduler to display in a web page?
Should be something like this:
string[] groups = myScheduler.JobGroupNames;
for (int i = 0; i < groups.Length; i++)
{
string[] names = myScheduler.GetJobNames(groups[i]);
for (int j = 0; j < names.Length; j++)
{
// groups[i]
// names[j]
}
}

Resources