Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Python For Unity Out of Process API Inconsistent Running Times

Discussion in 'Formats & External Tools Previews' started by npat15, Feb 24, 2021.

  1. npat15

    npat15

    Joined:
    Aug 21, 2020
    Posts:
    1
    Hi!

    I'm using Python for Unity to try and generate objects in a scene based on data from a csv file - for example, if we have three columns filled with numerical data, for each row in the csv, I'm generating an object in my scene with its x-coordinate as the value in column 1, the y-coordinate as the value in column 2, etc. While this could easily be done using C#, my goal is to perform some data analysis before generating my objects - being able to use python libraries like numpy and scipy for this could in theory save a great deal of time.

    I'm running the following script to do this:
    Code (CSharp):
    1.  // define column values
    2.             col1 = "0";
    3.             col2 = "1";
    4.             col3 = "2";
    5.  
    6.             string col_assingment_1 = "col1 = " + col1;
    7.             string col_assingment_2 = "col2 = " + col2;
    8.             string col_assingment_3 = "col3 = " + col3;
    9.  
    10.  
    11.             string[] args = {  
    12.             "import numpy as np",
    13.                                
    14.             "file = open('Assets/Datasets/normal_data.csv', 'r')",
    15.             "matrix = np.loadtxt(file, delimiter=',', skiprows=1)",
    16.  
    17.             col_assingment_1,
    18.             col_assingment_2,
    19.             col_assingment_3,
    20.  
    21.             "col1 = matrix[:, col1]",
    22.             "col2 = matrix[:, col2]",
    23.             "col3 = matrix[:, col3]",
    24.             "col_len = len(col1)",
    25.  
    26.             "file.close()"
    27.             };
    28.  
    29.             // time metric
    30.             System.DateTime epochStart = new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
    31.             int cur_time = (int)(System.DateTime.UtcNow - epochStart).TotalSeconds;
    32.  
    33.             Debug.Log("Starting Python executions at: " + cur_time);
    34.  
    35.             foreach (string arg in args)
    36.             {
    37.                 Debug.Log(arg);
    38.                 PythonRunner.CallServiceOnClient(ClientName, "exec", arg);
    39.             }  
    40.  
    41.             cur_time = (int)(System.DateTime.UtcNow - epochStart).TotalSeconds;
    42.             Debug.Log("Python evauluations starting at " + cur_time);
    43.  
    44.             // Py.GIL block needed for stability according to docs
    45.             using (Py.GIL()) {
    46.                 // get column arrays
    47.                 dynamic col1 = PythonRunner.CallServiceOnClient(ClientName, "eval", "col1");
    48.                 dynamic col2 = PythonRunner.CallServiceOnClient(ClientName, "eval", "col2");
    49.                 dynamic col3 = PythonRunner.CallServiceOnClient(ClientName, "eval", "col3");
    50.                 dynamic col_len = PythonRunner.CallServiceOnClient(ClientName, "eval", "col_len");
    51.  
    52.                 cur_time = (int)(System.DateTime.UtcNow - epochStart).TotalSeconds;
    53.                 Debug.Log("Starting instantiation at " + cur_time);
    54.                 instantiate_objects(col1, col2, col3, col_len);
    55.  
    56.                 cur_time = (int)(System.DateTime.UtcNow - epochStart).TotalSeconds;
    57.                 Debug.Log("Finished instantiation at " + cur_time);
    58.             }
    Where the "instantiate_objects" method looks something like this:
    Code (CSharp):
    1. public void instantiate_objects(dynamic xColumn, dynamic yColumn, dynamic zColumn, dynamic col_len)
    2.     {
    3.         // generate objects in scene based on column data
    4.  
    5.         for (int i = 0; i < (int)col_len; i++)
    6.         {
    7.             if (xColumn[i] != null && yColumn[i] != null && zColumn[i] != null)
    8.             {
    9.                 // create game object
    10.                 // TODO - work around hardcoding in sphere
    11.                 GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    12.                 obj.transform.position = new Vector3((float)xColumn[i], (float)yColumn[i], (float)zColumn[i]);
    13.             }
    14.         }
    15.     }
    While running this code does what I want, I've noticed some inconsistencies with running it. Sometimes, this script only takes a few seconds to run, and sometimes it takes up nearly 2 minutes! Added some Debug statements after certain parts of the code to try and see what was causing the bottleneck, and found this:

    1. My "exec" commands always run near-instantaneously
    2. My "eval" commands take 3-30 seconds to run
    3. Instantiating the objects takes 3-60 seconds to run.

    Does anyone know why I could be having such inconsistent runtimes, and more importantly, a way to consistently get the quickest runtimes possible? My best guesses are some kind of cache for the "eval" commands that make it sometimes run faster, but I have no clue why instantiating objects is behaving so erratically.

    Thank you!
     
  2. markvi

    markvi

    Joined:
    Oct 31, 2016
    Posts:
    118
    Hi, we just published Python for Unity 4.0.0-exp.5, which completely removes the out-of-process interpreter. Instead, in-process now works with native modules (including numpy & scipy). Please try it out!

    cheers,
    -Mark
     
  3. tran10

    tran10

    Joined:
    Nov 30, 2020
    Posts:
    13
    Hello,

    I have a script in C# for example:

    Code (CSharp):
    1. public class DraggableObject: MonoBehaviour
    2. {
    3. [INDENT]void OnMouseDown()
    4. {
    5. ....
    6. }[/INDENT]
    7. }

    And I want to use AddComponent to add this script C# to gameObject by script python like this:

    import UnityEngine as UE
    go = UE.GameObject.CreatePrimitive(UE.PrimitiveType.Cube)
    go.AddComponent(DraggableObject)


    But I have the error : name 'DraggableObject' is not defined.
    Do you have some advise? or I need to import DraggableObject.cs?

    Thank you so much for your reponse.

    Hoa.
     
  4. markvi

    markvi

    Joined:
    Oct 31, 2016
    Posts:
    118