Asynchronous jobs

In this tutorial we will learn how to run jobs asynchronously using Julia tasks. Asynchronous jobs allow for the code to continue with other computation while waiting for the quantum resources.

Julia tasks

Practical applications of quantum computing typically involve both classical and quantum computation. A quantum processor is indeed a hardware accelerator in this paradigm. In such scenarios, it might take some time for the quantum computer to run the circuit that was submitted to it.

In many cases, it is desirable to be able to continue with some classical computation while the program waits for the quantum hardware to complete its task. This is an example of asynchronous programming. We recommend you consult Julia's page on asynchronous programming if you are unfamiliar with this concept.

In Snowflurry, communicating with a quantum processor will yield execution every time it waits for a response from the quantum computer. This gives you the opportunity to perform work while the quantum computer is running your job.

Code

To provide maximum flexibility, Snowflurry does not impose any restrictions on how you parallelize your code. We cannot know what will be best for your code. That is up to you!

We will start by importing Snowflurry, building our circuit and defining our QPU as demonstrated in the Running a Circuit on a Real Hardware tutorial.

using Snowflurry

circuit = QuantumCircuit(qubit_count = 2, instructions = [
    hadamard(1),
    control_x(1, 2),
    readout(1, 1),
    readout(2, 2),
])

user = ENV["THUNDERHEAD_USER"]
token = ENV["THUNDERHEAD_API_TOKEN"]
host = ENV["THUNDERHEAD_HOST"]
project = ENV["THUNDERHEAD_PROJECT_ID"]
realm = ENV["THUNDERHEAD_REALM"]

qpu = AnyonYukonQPU(host = host, user = user, access_token = token, project_id = project, realm = realm)

Next, we are going to define and schedule our task.

shot_count = 200
task = Task(() -> run_job(qpu, circuit, shot_count))
schedule(task)
Warning

Note the last line above. It is important to schedule the task; otherwise, Julia will not know that it should start it!

Next, we need to yield execution of the current thread to the newly scheduled task to ensure that the scheduler starts with the task. Otherwise, the task will be scheduled, but it might not submit a job to the quantum computer any time soon! After yielding once, we can continue to do work before we fetch the results from that task.

yieldto(task)

# Simulate work by calculating the nth Fibonacci number slowly
function fibonacci(n)
  if n <= 2
    return 1
  end
  return fibonacci(n - 1) + fibonacci(n - 2)
end

fibonacci(30)

After we are done with our work, we can fetch the result of our job.

result = fetch(task)
println(result)

The full code is available at tutorials/asynchronous_jobs.jl