Why doesn't readLineSync works in an Isolate - dart

void func(String dummy) {
String? name = stdin.readLineSync();
print(name);
}
void main(List<String> args) {
Isolate.spawn(func, "Testing");
}
Why doesn't my program prompts a user input ..and waits for me to enter it. Instead, it simply exits. Can someone help me out with an explanation. Not sure where to look.
I did find a similar question posted where they were using a while loop and using readLineSync inside that..and because of single thread of dart ..it wasn't working there.

Dart programs terminates when the main-isolate does not have anymore to do, no events on the event queue, and does not subscribe to any event source which would result in new events being added to the event queue (like ReceivePort or Timer). It does not matter if spawned isolates are still being executed since they will just be killed.
You need to have the main-isolate to do something, or make the main-isolate subscribe to a signal from your spawned isolate using ReceivePort/SendPort as this will prevent the main-isolate from being terminated (since it subscribes to an event source which potentially could add new events on the event queue).
An example of using addOnExitListener on an Isolate object can be seen here:
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
void func(String dummy) {
print('Enter your name:');
final name = stdin.readLineSync();
print('Your name is: $name');
}
Future<void> main(List<String> args) async {
final onExitReceivePort = ReceivePort();
final isolate = await Isolate.spawn(func, "Testing");
isolate.addOnExitListener(
onExitReceivePort.sendPort,
response: 'ReadLineIsolateStopped',
);
// Listen on spawned isolate is stopped event
await for (final onExitEvent in onExitReceivePort) {
print('Got event: $onExitEvent');
onExitReceivePort.close();
}
}
We are here closing the onExitReceivePort as soon we gets one event (since the spawned isolate is then gone) which will stop our main-isolate and the rest of the program.

Related

Async-await in dart runs synchronously?

I am trying out the Future with async await for asynchronous programming.
The code i tested is a simple Future.
//order a new coffee perhaps!
Future<String> order(String newOrder){
final String Function() func = ()=> "${newOrder} is requested!";
final _order = Future.delayed(Duration(seconds: 5),func);
return _order;
}
When i run this code like a promise.
order("promised order")
.then((result) => print(result))
.catchError((err){
print(err.error);
});
This behaves like a asynchronous non-blocking code
However the same code when i run it with async/await behaves like a synchronous code and blocks all the other code, it waits 5 secs to run the next line.
void main(List<String> arguments) async {
final _myOrder = await order('Lattee mocha');
print(_myOrder);
//...all the other code waits for
}
So i thought async/await is same as futures, where non-blocking..
How come it blocks the other code execution ?
The whole point of the async/await pattern is to wait (hence await) until the Future completes and only then continue with this code execution.
Think of it as a way to not have endless .then() chains and much simplified error handling.
If you want to not wait, then you just leave out the await keyword. Obviously, if you don't (a)wait, you don't get the result.
You can still use classic .then() chains when it suits your purpose better in your program.
What people talk about when they say "non blocking" they mean that when the compiler sees the await keyword, it knows to keep the rest of the program, the event loops, animations etc running and not block the complete program.

can you run Isolate.spawn multiple times?

here is a simple code that I use to learn isolate, I spawn twice, but the second spawn does not show anything, any mistake here? Thanks
import 'dart:isolate';
Future<void> main() async {
print('start');
await Isolate.spawn(echo, 'Dart');
await Isolate.spawn(echo, 'Flutter'); // why this 2nd spawn not showing up?
print('end');
}
void echo(msg) {
print(msg);
}
Your program quits before the Isolate has done its job. You can confirm this if you add
await Future.delayed(Duration(seconds: 1));
somewhere towards the end of your program.
Setting up Isolates is often a bit challenging, with all the SendPort stuff etc.

Dart: Using JsObject and window API in an isolate

I am having some difficulties making use of isolates in Dart. The first problem is I wanted to use dart:js to use a javascript library in one of my isolates. I tried with the following code:
void runCode(SendPort sendPort)
{
print("still ok...");
JsObject object = new JsObject(context['jsCode']);
print("still ok?");
}
void main()
{
ReceivePort receivePort = new ReceivePort();
JsObject object = new JsObject(context['jsCode']);
print("ok so far");
Isolate.spawn(runCode, receivePort.sendPort);
}
The code runs as far as "still ok..." in the runCode function and breaks when I try to use JsObject.
The second problem was I wanted to use the fileSystem API in the isolate. So I tried the following:
void runCode(SendPort sendPort)
{
window.requestFileSystem.then((FileSystem filesytem) => print('ok'));
}
void main()
{
ReceivePort receivePort = new ReceivePort();
Isolate.spawn(runCode, receivePort.sendPort);
}
This second example breaks when I reach the filesystem.
I have read: Dart : Isolate not working when using html import and from here it suggests that dart:html cannot be used in an isolate. Is this the reason why the filesystem API will not work? Is this the same case for dart:js? Or am I completely missing something?
Thanks for any help!
I've read somewhere that only the main thread has access to the DOM, which would cause any other JS action to fail if not in the main thread.

Is it possible to detect 'dead' completers in Dart?

In the Dart vm the following code will not hang - the VM will exit:
import 'dart:async';
Future<Null> main() async {
await neverCompletes();
print('Will not run');
}
Future<Null> neverCompletes() => new Completer<Null>().future;
Is there any way to detect this situation? It would be easier to investigate if the VM hangs waiting for the Future. Any flags I can pass?

Is it possible to have multiple send and receive ports for Dart Isolates?

Is it possible to open a multiple send and receive ports for the same Isolate in Dart?
E.g. Following code sample would have created two isolates with each having its own send port. However, I was wondering if there is any way to create more than one send/receive ports for the same isolate and choose the receive port to send the message to.
#import('dart:isolate');
echo() {
}
main() {
var sendPort1 = spawnFunction(echo);
var sendPort2 = spawnFunction(echo);
}
You can actually create any number of ReceivePorts, and then as Matt said, any number of SendPorts per ReceivePort.
By default an isolate, including the main isolate, has a ReceivePort created and available through the port getter. This ReceivePort is connected to the SendPort returned from spawnFunction() and spawnUri(). But you can create a new ReceivePort with new ReceivePort(), then you can create as many connected SendPorts as you want via toSendPort(). To use them you send the new SendPort itself along with a message on the original SendPort you either got from spawnFunction(), or via ReceivePort.receive().
By doing this you can set up multiple "channels" between two isolates. I haven't played with it yet to see how this works in practice yet, I've been multiplexing channels via structured messages on one SendPort.
Note that you can create a ReceivePort in any isolate: the parent isolate or the child isolate. So if you want the partent to have two SendPorts to the child, then you need one from spawnFunction() and another that's passed from the child back to the parent in a message.
Here's your example changed to use multiple SendPorts. The steps:
main: Spawn an isolate
main: Send a message with a SendPort so that the isolate can send a message back
echo: Create a second ReceivePort in the isolate
echo: Receive a message in the isolate with a replyTo SendPort
echo: Create a SendPort from the ReceivePort and send it back
main: Receive the message and SendPort from echo
Now main() has two independent SendPorts to the isolate.
#import('dart:isolate');
echo() {
var port2 = new ReceivePort(); // 3
port2.receive((m, p) {
print("two: $m");
});
port.receive((m, p) { // 4
print("one: $m");
p.send("ack", port2.toSendPort()); // 5
});
}
main() {
port.receive((m, sendPort2) { // 6
sendPort2.send("hello 2");
});
var sendPort1 = spawnFunction(echo); // 1
sendPort1.send("hello 1", port.toSendPort()); // 2
}
This prints:
one: hello 1
two: hello 2
Whew!
While I'm not sure about multiple receive ports. You can create multiple send ports per receive port. This functionality is build into the ReceivePort class: ReceivePort.toSendPort
As indicated at the bottom of the help:
It is legal to create several SendPorts from the same ReceivePort.
Hope this helps.
The answer from Justin is basically right, but caused me some trouble because the isolate stopped responding after step 5 has been executed. So here is an updated version that actually worked in my context:
import 'dart:isolate';
echo() {
var port2 = new ReceivePort();
port2.receive((m, p) {
print("two: $m");
});
port.receive((m, p) {
print("one: $m");
p.send(port2.toSendPort());
});
}
main() {
var sendPort1 = spawnFunction(echo);
sendPort1.call("hello 1").then((newPort)=>newPort.send("hello 2"));
}
The major difference is simply that the port is send as message rather than using the replyTo field. This also allows for a more compact code as the other receiving Port is not required.

Resources