Using a shared file to exchange data between Unity and Python.
- Can only exchange booleans, integers, floats, strings and byte arrays.
- Easy to add new types.
- Lightweight : Only one script on C# and one script on Python
- Shared memory not work across machines like sockets would.
- Shared memory has the potential to be extremely fast when the volume of data is large.
Via the Package Manager. Add a dependency to the manifest.json of your project:
{
"dependencies": {
"com.python-unity-shared-memory": "https://github.com/vincentpierre/PythonUnitySharedMemory.git?path=/com.python-unity-shared-memory"
}
}
Alternatively, you can clone the repository locally and use you local path.
Clone the repository and run the command
pip install -e python_unity_shared_memory
The API is meant to be identical between C# and Python.
from python_unity_shared_memory import SharedMemory, delete_files
sm = SharedMemory(
prefix="my-file", # The ID of the shared memory
capacity=100, # The number of bytes of the file
create_new=False, # Wether to create the file or open it
timeout=30) # How low to timeout (-1 means no timeout)
using PythonUnitySharedMemory;
var sm = new SharedMemory(
prefix:"my-file", // The ID of the shared memory
capacity:100, // The number of bytes of the file
createNew:true, // Wether to create the file or open it
timeout:30); // How low to timeout (-1 means no timeout)
Note that :
- In the example above, the id "my-file" need to be identical for the two shared memory partitions to communicate.
- You can open as many shared memory files as you want.
- The
capacitymust be the same on both sizes. - In this case, Unity creates the share memory and Python joins it (see
create_new/createNewarguments) timeoutis expressed in seconds- A negative
timeoutmeans no timeout
sm.resize(new_capacity)
sm.Resize(newCapacity)
If your shared memory partition is too small, you can resize it. If you do, the new capacity must be strictly greater than the previous one. When resizing, a new file will be created and both SharedMemory objects will switch to using the new one. This operation is expensive, it is recommended to use it only when necessary and to allocate a greater capacity than needed.
Available read methods take as argument an offset in the shared memory and return a tuple of (value, new_offset):
read_boolread_int32read_float32read_stringread_bytes(takes as input an offset and a length argument)
And the write methods take as argument an offset and a value. They will return the new offset.
write_boolwrite_int32write_float32write_stringwrite_bytes
For example:
new_offset = sm.write_string(offset, "my-string")
my_string, new_offset = sm.read_string(offset)
assert my_string == "my-string"
Available read methods take as argument an offset in the shared memory and return a tuple of (value, new_offset):
ReadBoolReadInt32ReadFloat32ReadStringReadBytes(takes as input an offset and a length argument)
And the write methods take as argument an offset and a value. They will return the new offset.
WriteBoolWriteInt32WriteFloat32WriteStringWriteBytes
For example:
newOffset = sm.WriteString(offset, "my-string")
(str my_string, int new_offset) = sm.ReadString(offset)
assert my_string == "my-string"
The reason the read and write methods return the new offset is to make it easy to chain reads and writes:
offset = 0
value_1, offset = sm.read_int32(offset) # offset is now 4
value_2, offset = sm.read_float32(offset) # offset is now 8
Note also that C# tuples are accessed with the properties tuple.Item1 and tuple.Item2 while Python can access tuples like arrays tuple[0] and tuple[1]
The give_control() and GiveControl() methods will signal the other process that it is their turn to edit the file. Until the other process gives control back, the current process will be waiting.
It is possible to pass an optional argument wait=False to give_control on both Python and C#. In this case the control will be passed to the other process but the current process will not be blocked. You can manually block the process until control is given back with wait_unblocked/WaitUnblocked. Note that if you give back control without waiting and edit the shared memory before calling wait_unblocked you expose yourself to race conditions.
You can call the close()/Close() methods to signal the file is no longer being used and call delete()/Delete() to delete it. If you want to manually delete your old shared memory files, you can call the method delete_files(prefix) on Python and SharedMemory.DeleteFiles(prefix) on C#.