Asynchronous Methods

From Phidgets Support

What Are Asynchronous Methods?

Asynchronous methods allow you to send commands to a device without waiting for return codes.


When calling a typical non-asynchronous method, your program must wait for the return code, blocking the rest of your program’s operation.

Async methods typical flow.png


When using an asynchronous method, your program can immediately continue executing and handle the return code in an asynchronous handler.

Async methods async flow.png

When Should I Use Asynchronous Methods?

There are two situations where asynchronous methods may be beneficial:

  1. When sending commands to multiple channels on the same device
  2. When sending commands to multiple channels on different devices

Multiple Channels Example

32x Isolated LED Phidget (LED1000_0)

The 32x Isolated LED Phidget features 32 channels, one for each LED. To turn all the LEDs on or off simultaneously, 32 sequential commands are necessary (one for each channel). In this situation, using asynchronous methods can drastically improve the performance of your application.

Multiple Devices Example

The Isolated 12-bit Voltage Output Phidget is a single-channel device. If two or more of these devices were used in an application, it may be beneficial to use asynchronous methods.

How Do I Use Asynchronous Methods?

Asynchronous methods are comprised of two parts:

  • The asynchronous API call
  • The asynchronous handler

When calling an asynchronous method, you must assign an asynchronous handler. The Phidget22 libraries will then initiate the command and immediately return. The asynchronous handler will be called once the relevant communications have been completed to provide the return code from the device.

Code Example

The code below provides a simple demonstration of how asynchronous methods can be used (while avoiding overloading).

from Phidget22.Phidget import *
from Phidget22.Devices.DigitalOutput import *
from Phidget22.ErrorCode import *
import time

def main():
    digitalOutput0 = DigitalOutput()

    digitalOutput0.openWaitForAttachment(5000)

    #Assign new variables to track the number of calls made vs completed
    digitalOutput0.AsyncCalls = 0
    digitalOutput0.AsyncComplete = 0
    def AsyncResult(ch, res, details):
        ch.AsyncComplete += 1
        print("Async Complete:" + str(ch.AsyncComplete))
        if res != ErrorCode.EPHIDGET_OK:
            print("Async failure: %i : %s" % (res, details))
    
    while(1): #some loop condition
        #Here we check if the previous asynchronous call has completed before issuing a new one
        #If you had multiple asynchronous calls to make, you could (for example) give each its
        #own counter, or call a new batch of them once an entire set completes
        if(digitalOutput0.AsyncCalls == digitalOutput0.AsyncComplete):
            digitalOutput0.AsyncCalls += 1
            digitalOutput0.setDutyCycle_async(1, AsyncResult)
            # NOTE: Make sure to wait for async call to complete before closing the channel
        
        #Do other work here...

    digitalOutput0.close()

main()

import com.phidget22.*;
import java.io.IOException;

public class JavaApplication11 {

    static int asyncCalls = 0;
    static int asyncComplete = 0;
    
    public static void main(String[] args) throws Exception {
        
        Phidget.resetLibrary();
        DigitalOutput digitalOutput0 = new DigitalOutput();

        digitalOutput0.open(5000);
        
        while(asyncComplete < 1000) { //Some loop condition
            //Here we check if the previous asynchronous call has completed before issuing a new one
            //If you had multiple asynchronous calls to make, you could (for example) give each its
            //own counter, or call a new batch of them once an entire set completes
            if(asyncCalls == asyncComplete) {
                asyncCalls++;
                digitalOutput0.setDutyCycle(1, new AsyncListener() {
                    public void onAsyncCallback(AsyncResult ar) {
                        if (ar.getReturnCode() == ErrorCode.SUCCESS) {
                            asyncComplete++;
                            System.out.println("Async Complete: " + asyncComplete);
                        }
                        else
                            System.out.println("Async Failure: " + ar);
                    }
                });
                // NOTE: Make sure to wait for async call to complete before closing the channel
            }
            
            //Do other work here...
            Thread.sleep(1);
        }

        digitalOutput0.close();
    }
}

using System;
using Phidget22;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            DigitalOutput digitalOutput0 = new DigitalOutput();

            digitalOutput0.Open(5000);

            digitalOutput0.DutyCycle = 1;

            int asyncCalls = 0;
            int asyncComplete = 0;
            double dutyCycle = 0.1;
            while (true) /* Some loop condition */
            {
                //Here we check if the previous asynchronous call has completed before issuing a new one
                //If you had multiple asynchronous calls to make, you could (for example) give each its
                //own counter, or call a new batch of them once an entire set completes
                if (asyncCalls == asyncComplete)
                {
                    asyncCalls++;
                    digitalOutput0.BeginSetDutyCycle(dutyCycle, delegate (IAsyncResult result)
                    {
                        try
                        {
                            asyncComplete++;
                            digitalOutput0.EndSetDutyCycle(result);
                            Console.WriteLine("Async Complete: " + asyncComplete.ToString());
                        }
                        catch (PhidgetException ex)
                        {
                            Console.WriteLine("Async Failure: " + ex.Message);
                        }
                    }, null);
                }

                /*
                 *  Do other work were
                 */
            }
            digitalOutput0.Close();
        }
    }
}

#include <phidget22.h>
#include <stdio.h>

void CCONV setDutyCycleDone(PhidgetHandle phid, void *ctx, PhidgetReturnCode res) {
    int *asyncComplete = (int*)ctx;
    (*asyncComplete)++;
    printf("Async Complete : %d\n", *asyncComplete);
}

int main() {    
    PhidgetDigitalOutputHandle digitalOutput0;
    int asyncComplete;
    int asyncCalls;

    PhidgetDigitalOutput_create(&digitalOutput0);

    Phidget_openWaitForAttachment((PhidgetHandle)digitalOutput0, 5000);

    PhidgetDigitalOutput_setDutyCycle(digitalOutput0, 1);

    asyncComplete = 0;
    asyncCalls = 0;
    while (1) { //Some loop condition

        //Here we check if the previous asynchronous call has completed before issuing a new one
        //If you had multiple asynchronous calls to make, you could (for example) give each its
        //own counter, or call a new batch of them once an entire set completes
        if (asyncCalls == asyncComplete) {
            asyncCalls++;
            PhidgetDigitalOutput_setDutyCycle_async(digitalOutput0, 1, setDutyCycleDone, &asyncComplete);
        }

        //Do other work here...

    }
    Phidget_close((PhidgetHandle)digitalOutput0);

    PhidgetDigitalOutput_delete(&digitalOutput0);
}

Other Considerations

Overloading

If asynchronous methods are called faster than they can be dispatched, they will be added to a queue. In extreme cases, if the queue grows large enough, newer calls will be dropped and your async handler will complete with Phidget Error 0x10 NoSpace.

Single Device, Single Channel

Asynchronous commands are not recommended when using a single device and a single channel. Multiple asynchronous calls to the same channel will be queued and issued one at a time as return codes are received for each, providing no benefit to your application.

Network Delays

If you are accessing your device(s) over a network connection with high latency, you may benefit from using asynchronous methods.

Callback Handlers

When programming using the C language, a callback handler is required. If a callback handler is not provided, the method will not run asynchronously. In all other programming languages, a callback handler is recommended but optional.

VINT Communication Speed

Asynchronous methods are particularly useful on VINT devices with lower communication speeds. If you are working with USB devices or higher-speed VINT devices, the impact of asynchronous commands will be less significant.