6.11 Parallel optimization

In this section we demonstrate the simplest possible multi-threading setup to run multiple MOSEK optimizations in parallel. All tasks must be created using the same MOSEK environment. One license token checked out by the environment will be shared by the tasks.

We first define a simple method that runs a number of optimization tasks in parallel, using the standard multi-threading setup available in the language.

Listing 6.41 Parallel optimization of a list of tasks. Click here to download.
    /** Takes a list of tasks and optimizes them in parallel threads. The
        response code and termination ocde from each optimization is
        stored in ``res`` and ``trm``.
     */
    public static void paropt(mosek.Task[]    tasks,
                              mosek.rescode[] res,
                              mosek.rescode[] trm)
    {
      var n = tasks.Length;
      var jobs = new System.Threading.Tasks.Task[n];
     
      // Initialize
      for (var i = 0; i < n; ++i) 
      {
        res[i] = mosek.rescode.err_unknown;
        trm[i] = mosek.rescode.err_unknown;
      }

      // Start parallel optimizations, one per task
      for (var i = 0; i < n; ++i)
      {
        int num = i;
        jobs[i] = System.Threading.Tasks.Task.Factory.StartNew( () => {
          try
          {
            trm[num] = tasks[num].optimize();
            res[num] = mosek.rescode.ok;
          }
          catch (mosek.Exception e)
          {
            trm[num] = mosek.rescode.err_unknown;
            res[num] = e.Code;
          }
        } );
      }

      // Join all threads
      foreach (var j in jobs)
        j.Wait();
    }

It remains to call the method with a few different tasks. When optimizing many task in parallel it usually makes sense to solve each task using one thread to avoid additional multitasking overhead. When all tasks complete we access the solutions in the standard way.

Listing 6.42 Calling the parallel optimizer. Click here to download.
    /** Example of how to use ``paropt``. 
        Optimizes tasks whose names were read from command line.
     */
    public static void Main(string[] argv)
    {
      int n = argv.Length;
      mosek.Task[]  t      = new mosek.Task[n];
      mosek.rescode[] res  = new mosek.rescode[n];
      mosek.rescode[] trm  = new mosek.rescode[n];
  
      using (var env = new mosek.Env())
      {
        for(int i = 0; i < n; i++) 
        {
          t[i] = new mosek.Task(env);
          t[i].readdata(argv[i]);
          // Each task will be single-threaded
          t[i].putintparam(mosek.iparam.intpnt_multi_thread, mosek.onoffkey.off);
        }

        paropt(t, res, trm);

        for(int i = 0; i < n; i++) 
          Console.WriteLine("Task  {0}  res {1}   trm {2}   obj_val  {3}  time {4}", 
            i, 
            res[i], 
            trm[i],  
            t[i].getdouinf(mosek.dinfitem.intpnt_primal_obj),
            t[i].getdouinf(mosek.dinfitem.optimizer_time));
      }
    }

Another, slightly more advanced application of the parallel optimizer is presented in Sec. 11.3 (Concurrent optimizer).