There are two basic types of methods in the Parallels Python API: synchronous and asynchronous. When a synchronous method is invoked, it completes executing before returning to the caller. An asynchronous method starts a job in the background and returns to the caller immediately.
Synchronous Methods
A typical synchronous method returns the result directly to the caller as soon as it completes executing. In the example below, the Vm.create_device()
method creates and returns a new device object of the specified type. The new_dev
variable receives the created object reference.
new_dev = vm.create_device(consts.PDE_OPTICAL_DISK)
Synchronous methods throw the prlsdkapi.prlsdk.ParallelsError
exception.
Asynchronous Methods
Asynchronous methods in the Parallels Python API return one of the two objects: prlsdkapi.Job
or prlsdkapi.Result
. Methods that obtain information return the Result
object. Methods that perform actions return the Job
object.
A Job
object is a reference to the background job that the asynchronous method has started. A job is executed in the background and may take some time to finish. In other languages, asynchronous jobs are usually handled using callbacks (or event handlers). Unfortunately, callbacks are not available in the Parallels Python API. You have two ways of handling asynchronous jobs in your application. The first one is implementing a global loop in your application and checking the results of an asynchronous job in every iteration. Another approach is to call an asynchronous method synchronously. The following explains how the second approach works.
The Job
class has the wait()
method. You can invoke this method as soon as you receive the Job
object. What this will do is suspend the execution of your main program and wait for the job to finish. As soon as the job is finished, the wait()
method will return to the caller. The results of the operation will also be ready at that time. The following code snippet illustrates this.
# Start a virtual machine. This is an asynchronous call.
job = vm.start()
# Wait for the job to complete.
job.wait()
print vm.name + " was started."
You can also use this syntax:
# Start a virtual machine, wait for the job to complete.
vm.start().wait()
print vm.name + " was started."
There are two main reasons why you would want to obtain a Job
object from your asynchronous method as shown in the first example:
wait()
method at some later moment.Job
class. The methods and properties are described in the following table:
|
This method can be used to cancel the job before it is finished. |
|
This property can be used to determine the job status. |
|
This property can be used to obtain a code identifying the type of the operation being performed. The property contains one of the constants from the |
As we said earlier, asynchronous methods in the Parallels Python API return either the prlsdkapi.Job
object or the prlsdkapi.Result
object. The Result
class provides almost identical set of methods and properties as the Job
class and is used similarly. An asynchronous method that returns a Result
object also starts a job in the background and returns immediately to the caller. You have the same options here: loop infinitely and check if the job has completed or use the wait()
function to emulate the synchronous method invocation. Consider the following example.
In this example, we will obtain the list of virtual machines registered with the given Parallels Service. The Vm.get_vm_list()
method is used to perform this task. The method returns an instance of Result
class populated with prlsdskapi.Vm
objects. Individual Vm
objects can be used to obtain information about individual virtual machines.
# Obtain a list of virtual machines.
# Wait for the asynchronous job to complete.
# On method return, the result variable will contain
# the Result object.
result = server.get_vm_list().wait()
# Get the number of parameters (virtual machine objects)
# from the result object.
count = result.get_params_count()
# Iterate through the list and display the
# virtual machine name on the screen.
for i in range(0, count):
vm = result.get_param(i)
print vm.name
But what will happen if we don't use the wait()
method? Let's examine this scenario. First of all, if you don't have a global loop in your program, it may simply exit before the asynchronous job is finished and you will loose the results or may experience other unpredictable problems. If you do have a loop (or some other mechanism that prevents your program from exiting) then you can do a couple of things. You can check if the job has finished by examining the finished
property of either the Job
or the Result
object (whichever applies). If the value is True
then the job has finished. If the value is False
then it is still running. You can also simply try and read the data from the object. Both, the Job
and the Result
objects have a built-in mechanism that will invoke the wait()
method automatically if you try to access them before the job is finished. Let's use the example above to illustrate this scenario.
# Obtain a list of virtual machines.
# Please note that we are not using the wait() method.
result = server.get_vm_list()
# This is the first time we try to access the result object, so
# the wait() method will be invoked on it automatically.
count = result.get_params_count()
# Iterate through the list and display the
# virtual machine name on the screen.
for i in range(0, count):
vm = result.get_param(i)
print vm.name
When reading the data using the class properties, you should be aware that, in most cases, the properties are using the corresponding methods of the same class to obtain the data. This means that the data may not be available locally yet and that the method invoked by a property will try to obtain it from the server side. To prevent data corruption, the wait()
method will also be invoked automatically and transparently to the programmer. You should plan your application logic with this knowledge in mind.
Asynchronous methods throw the prlsdkapi.PrlSDKAsyncError
exceptions.