Dart Tutorial

Dart Tutorial Single-Page Application Architecture Dart Features Dart Installation Guide Dart Basic Program Dart Syntax Dart Keywords Dart Variables Dart Comments Dart Standard Input Output Dart Important Concepts

Data Types

Built-in Data Types Numbers Strings Booleans Lists Sets Maps Runes and Graphemes Symbols Enumerations Constants Queues

Other data types

Objects Future and stream Iterable Miscellaneous types

OPERATORS

Precedence and associativity Arithmetic operators Equality and Relational operators Type Test Operators Assignment Operators Logical Operators Bitwise and Shift Operators Miscellaneous operators

Control Flow Statements

Introduction If statement If-else statement If-else-if statement Loops Switch and case Dart Break And Continue Assert In Dart

FUNCTIONS

Dart function Types of Functions Anonymous function main( ) function Lexical scope and closure Recursion Common Collection Methods

Object Oriented Concepts

Dart Object-Oriented Concepts Dart Classes Dart Constructors Dart This Keyword Dart Super Keyword Static Members Method Overriding Dart Interfaces Inheritance Dart Abstract Classes Dart Builder Classes Dart Callable Classes

Dart Type System

Dart Type System Dart Soundness Dart Type Inference

MISCELLANEOUS

Dart Isolates Dart Typedef Dart Metadata Dart Packages Dart Generics Dart Generators Dart Concurrency Dart Unit Testing Dart Html Dom Dart URIs Dart Extends, With and Implements Keywords Dart Optional Parameters Rust Vs Dart C++ vs Dart Golang Vs Dart Dart Basics Exception Handling

Dart Isolates

Dart successfully supports asynchronous programming which runs our program without any hindrance. This asynchronous programming is used to achieve concurrency. Dart supports concurrent programming with features such as ‘ async-await ’, ‘ isolates ’, and classes such as ‘ Future ’ and ‘ Stream ’.

Within the app, all Dart code runs in an isolate. Each Dart isolate one set of killings and does not share the same variables with other separators. To communicate with one another, isolate is used to convey a message. Although the single Dart model is made up of basic elements such as the processes and series provided by the operating system, the use of the Dart VM of these articles is the implementation details that this page does not discuss.

Dart has solved a version of the series. The common implementation of "Series" or "Isolates" differ from each other. Isolate works differently compared to Thread. Separated are independent employees who do not share memory, but instead communicate by transmitting messages to channels. As isolate completes its function by conveying a message it thus needs a way to integrate the message.

The connection between the isolates is made through a passing message as a client and server. Helps the system to use a multicore microprocessor outside the box.

Dart offers a dart: a split package to use isolate in our system. Provides a single-strand Dart code capture solution and allows the app to make the most of the available hardware.

Create and Start an Isolate :

The ' spawn( ) ' method is used to create an isolate. It must be declared with an ' entry point ' with a single parameter. This parameter displays a port which isolate use to refer back notification message.

Let's understand the following example -

Example 1 -

import 'dart:isolate' ;    
// function containing the message to be printed
void func( var message )
{   
   print( ' We are executing this message from func( ) : ${ message } ' ) ;   
}    
void main( )
{   
   Isolate.spawn( func,' This is an isolate program ! ' ) ;   
   Isolate.spawn( func,' We are executing from main( ) function ! ' ) ;   
   Isolate.spawn( func,' These messages are referring to func( ) function ! ' ) ;   
     
   print( ' Executing from the main1( ) function ! ' ) ;   
   print( ' Executing from the main2( ) function ! ' ) ;   
   print( ' Executing from the main3( ) function ! ' ) ;   
}  

Output 1 :

 Executing from the main1( ) function ! 
 Executing from the main2( ) function ! 
 Executing from the main3( ) function ! 
 We are executing this message from func( ) :  These messages are referring to func( ) function !
 We are executing this message from func( ) :  This is an isolate program !

Output 2 :

 Executing from the main1( ) function ! 
 Executing from the main2( ) function ! 
 Executing from the main3( ) function ! 
 We are executing this message from func( ) :  This is an isolate program !
 We are executing this message from func( ) :  We are executing from main( ) function !

Output 3 :

 Executing from the main1( ) function ! 
 Executing from the main2( ) function ! 
 Executing from the main3( ) function ! 
 We are executing this message from func( ) :  We are executing from main( ) function !
 We are executing this message from func( ) :  This is an isolate program !

Explanation :

The ' spawn( ) ' method used in the above program is the method of the ' Isolate ' class. It executed the function named ‘ func( ) ’ in parallel to the execution of remaining code. It takes two parameters. The function that we want to spawn and the string that will be passed to the function spawned.

We have two functions named ' func( ) ' and ' main( ) ' function might not run in the same order each time. The output will be different every time we run the code written below which you can see in the second and third outputs as well.

Note - NULL value could also be passed if there is no object created to pass to the function spawned.

Let's understand the another example -

Example – 2 :

import 'dart:isolate' ;
import 'dart:io';    
void start( ) async {
  ReceivePort receiverPort = ReceivePort( ) ; // Port for isolate to receive message.
  isolate = await Isolate.spawn( f, receiverPort.sendPort ) ;
  receiverPort.listen( ( data ) {
    stdout.write( ' Receiving the : ' + data + ', ' ) ;
  } ) ;
}
void f( SendPort sendPort ) {
  var count = 1 ;
// This function sets the times to 1 second which enables the message
// to be printed after every second
  Timer.periodic( new Duration( seconds : 1), ( Timer t ) {
    count++ ;
    // initialising the message
    var msg = ' Notification ' + count.toString( ) ;
    // displaying the message
    stdout.write( ' Sending the : ' + msg + ' - ' ) ;
    sendPort.send( msg ) ;
  } ) ;
}

Explanation :

We have shown the original method as async because wan can wait for a response from the birth of the isolate and keep a reference for the new isolate. It is important if we want to kill active isolate. We have passed two parameters in the ‘ spawn( ) ’ method, the first parameter ‘ runTimer( ) ’ method,  that is a callback function to execute ‘ runTimer( ) ’ and the second sendPort parameter which is a callback function and it will used to send message back to the caller. The ‘ start( ) ’ method starts listening to the receiverPort to receive the message from the isolate. When it receives a message, it will print as a console output.

The ' runTimer( ) ' method keeps track of the timer running every second and simultaneously updates the counter by 1. It sends the notification of the corresponding message via the port through which it received the message when the isolate was just started.

Stop an Isolate :

The method used to stop an isolate currently being executed is a ‘ kill( ) ’ method. This function is provided in the Dart package ‘ dart:isolate ’.

Let's understand the following example.

Example 3 -

void stop( ) {
  if ( isolate != null ) {
    stdout.writeln( ' Terminating the isolate . . . . .  ' ) ;
    isolate.kill( priority: Isolate.immediate ) ;
    isolate = ‘ NULL ’ ;
  }
}

Explanation :

A ‘ stop( ) ’ method has been initialized in the above example to destroy the isolate currently executed or running and to set the reference of that isolate to ‘ null ’. The priority of isolate has been set to ‘ immediate ’ which prompts the termination of the isolate very quickly.

Complete Program :

import 'dart:io' ;  
import 'dart:async' ;  
import 'dart:isolate' ;
Isolate isolate ;    
// Starting the isolate   
void start( ) async {  
         ReceivePort  receiverPort = ReceivePort( ) ;   // Port for isolate to receive message.  
         isolate = await Isolate.spawn( f, receiverPort.sendPort ) ;  
         receiverPort.listen( ( data ) {  
               stdout.write( ' Receiving the : ' + data + ', ' ) ;  
  
     } ) ;  
}  
void f( SendPort sendPort ) {  
var count = 1 ; 
// This function sets the times to 1 second which enables the message
// to be printed after every second 
Timer.periodic( new Duration( seconds : 1 ), ( Timer t ) {  
     count++ ;  
     // initialising the message
     var msg = ' Notification ' + count.toString( ) ;  
     // displaying the message
     stdout.write( ' Sending the : ' + msg + ' -' ) ;  
     sendPort.send( msg ) ;  
  } ) ;
}  
// Stopping the isolate using the stop( ) function.  
void stop( ) {  
    if ( isolate != null ) {  
          stdout.writeln( ' Terminating the isolate . . . . .  ' ) ;  
          isolate.kill( priority : Isolate.immediate ) ;  
          isolate = null ;   
     }  
}  
void main( ) async {  
    stdout.writeln( ' Isolate execution begins : ' ) ;  
    await start( ) ;  
    stdout.writeln( ' Press a key to terminate execution !  ' ) ;  
    await stdin.first ;  
    stop( ) ;  
    stdout.writeln( ' Successfully executed ! ' ) ;  
    exit( 0 ) ;  
}  

Output :

Isolate execution begins : 
Press a key to terminate execution !
Sending the : Notification 1 – Receiving the : Notification 1, Sending the : Notification 2 – Receiving the : Notification 2,
Successfully executed !

Constructors :

  1. Isolate( SendPort controlPort, { Capability? pauseCapability, Capability? terminateCapability } ) : This constructor creates a new object of ‘ Isolate ’ class with a restricted set of capabilities.

Properties :

  1. controlPort → SendPort : Control port is used to send control messages to the isolate.
  2. debugName → String? : This property respresents the name of the Isolate displayed for debug purposes. 
  3. errors → Stream : This propertyreturns a broadcast stream of uncaught errors from the isolate. 
  4. hashCode → int : This property returnsthe hash code for this object. 
  5. pauseCapability → Capability? : This property has thecapability granting the ability to pause the isolate. 
  6. runtimeType → Type :  This property offersa representation of the runtime type of the object.
  7. terminateCapability → Capability? : This property has thecapability granting the ability to terminate the isolate. 

Methods :

  1. addErrorListener( SendPort port ) → void : This method requests that uncaught errors of the isolate are sent back to port. 
  2. addOnExitListener( SendPort responsePort, { Object? Response } ) → void : This method requests an exit message on responsePort when the isolate terminates. 
  3. kill( { int priority = beforeNextEvent } ) → void : This method requests the isolate to shut down. 
  4. noSuchMethod( Invocation invocation ) → dynamic : This method is invoked when a non-existent method or property is accessed. 
  5. pause( [ Capability? resumeCapability ] ) → Capability : This method requests for pausing the isolate. 
  6. ping( SendPort responsePort, { Object? response, int priority = immediate } ) → void : This method requests that the isolate send response on the responsePort. 
  7. removeErrorListener( SendPort port ) → void : This method stops listening for uncaught errors from the isolate. 
  8. removeOnExitListener( SendPort responsePort ) → void : This method stops listening for exit messages from the isolate. 
  9. resume( Capability resumeCapability ) → void : This method resumes a paused isolate. 
  10. setErrorsFatal( bool errorsAreFatal ) → void :This method determines whether the errors not caught will truncate the isolate. 
  11. toString( ) → String : This property refers to a string representation of this object. 

Operators :

  1. operator ==( Object other ) → bool : This is an equality operator. 

Static Properties :

  1. current → Isolate : This property regers to an Isolate object representing the current isolate. 
  2. packageConfig → Future< Uri ? > : This property refers to the location of the package configuration of the current isolate, if any. 
  3. packageRoot → Future< Uri ? > : This property refers to the package root of the current isolate, if there are any. @Deprecated( ' packages/ directory resolution is not supported in Dart 2. ' ).

Static Methods :

  1. exit( [ SendPort? finalMessagePort, Object? Message ] ) → Never : This method truncates the currently active isolate synchronously. 
  2. resolvePackageUri( Uri packageUri ) → Future< Uri ? > : Maps a package : URI to a non-package Uri. 
  3. spawn< T >( void entryPoint( T message ), T message, { bool paused = false, bool errorsAreFatal = true, SendPort? onExit, SendPort? onError, String? debugName } ) → Future< Isolate > : This method creates and spawns an isolate that shares the same code as the current isolate. 
  4. spawnUri(Uri uri, List<String> args, dynamic message, {bool paused = false, SendPort? onExit, SendPort? onError, bool errorsAreFatal = true, bool? checked, Map<String, String>? environment, Uri? packageRoot, Uri? packageConfig, bool automaticPackageResolution = false, String? debugName}) → Future<Isolate> : This method creates and spawns an isolate that runs the code from the library with the specified URI. 

Constants :

  1. beforeNextEvent → const int : Argument to ping and kill : Ask for an action before the next event.
  2. immediate → const int : Argument to ping and kill : Ask for an immediate action.

How isolates work ?

Most modern machines have CPUs with multiple cores. To take advantage of all these cores, engineers sometimes use shared memory threads that run simultaneously. However, shared-state concurrency is error prone and can lead to complicated code. Instead of threads, all Dart code works inside isolate. Each isolate has its own set of heaps, ensuring that no locally located region is accessible to any other isolated region. Because no memory is shared, you don't have to worry about the mute or the locks.

Using isolate, your Dart code can perform multiple independent tasks at once, using additional processor cores when available. Isolates are similar to threads or processes, but each isolate has its own memory and a single thread using an event loop.

The main isolate :

You usually do not need to think about isolates at all. The standard Dart application applies all of its code to the main application isolate, as shown in the following diagram:

Dart Isolates

Even stand-alone programs can do well by using async-await to wait for asynchronous operation to be completed before proceeding to the next line of code. A well-behaved app starts fast, reaching the event cycle very quickly. The app then responds to each online event quickly, using synchronized functions as needed.

The isolate life cycle :

As the following figure shows, all isolate starts using a specific Dart code, such as a main( ) function. This Dart code may enrol other event audience - input of user input or I / O file, for example. When the first isolate activity returns, the isolate remains nearby when it needs to host events. After handling the events, the isolate comes out.

Dart Isolates