Skip to content

Multithreading

Eli Belash edited this page Dec 4, 2019 · 15 revisions

Tensorflow.NET is thread-safe, our multithreading model is thread-wide Session and Graph; meaning tf.get_default_graph/session() are unique to the thread they are executed in.

We chose this model because a dominant portion of our api does not accept Graph as a parameter, instead it accesses tf.get_default_graph() to initialize an Operation in it.
This allows cleaner and similar code to Python and still having complete isolation between threads.

Due to lack of documentation in Tensorflow regarding their c_api, we don't know which of their API is threadsafe therefore some issues such as access violation or other types of memory corruption might occur. Let us know about it and we'll work to get it fixed. In most cases wrapping code with lock (Locks.ProcessWide) solves the problem.

Capabilities

  • Initialize sessions, graphs and operations in completely isolation from other threads.
  • Call your_session.run(...) parallely and in separate threads regardless to the defaults in the executing thread.

Limitations

  • When writing a model, it has to be done in the same thread unless yourgraph.as_default() is called in a different thread.
    For example : You can't start a model and then continue it in a Task unless you call graph.as_default() and session.as_default() before doing so.
  • Tensorflow's c_api for the most part is thread-safe, calls of status.Check() sometimes to be inside a process-wide lock, for example:
    lock (Locks.ProcessWide) 
    { 
        var status = new Status(); 
        c_api.someapicall(); 
        status.Check(true); 
    }
  • Lack of support for TPL. Task.Run(...) because TaskScheduler can't assure the tasks will be run in different threads, Only way to use Task with Tensorflow.NET is to initiate tasks like this:
    Task.Factory.StartNew(() => { ... }, TaskCreationOptions.LongRunning);
    You must create the session and graph only inside that Action passed to the Task factory. In order to use the graph and session created inside the task on an outside code/different thread, call sess.as_default() and graph.as_default() first.
  • If a Graph or Session were created in thread x, in order to use them in thread y the developer must call Session.as_default() and Graph.as_default() first before using it.

Jupyter Notebooks

Call tf.enforce_singlethreading() in the begginging of your notebook.
It was created specially for specific cases like Jupyter notebook where different threads can call your code chunks. This will cause the library to always behave as if it is run on a single thread but does not use any locking calls.
Simply put to words: makes the library forcefully singlethreaded but unsafe multithreaded calls.

Clone this wiki locally