When you’re working with multiple processes in Python, they each run in their own space. This means they don’t naturally share data. If you want them to talk to each other or work on the same data, you need Inter-Process Communication (IPC).
One powerful way to share data is through shared memory. Instead of sending messages or using files, you let processes read and write to the same memory directly. It’s fast and efficient.
Python makes this easy with the multiprocessing
module, especially its sharedctypes
tools. These let you create shared objects like numbers and arrays, and access them from different processes without copying data around.
In this guide, you’ll learn how to use:
Value
andRawValue
to share single data valuesArray
andRawArray
to share sequences of data
Each section comes with a fun, practical example so you can see exactly how it works in real code.
Setting Up: Importing What We Need
Before we dive into the code, let’s import the tools we’ll use in each example. These come from Python’s standard library, so you don’t need to install anything extra.
We’ll use:
multiprocessing
: to run multiple processesctypes
: to define the data types for shared memorytime
: to simulate delays in our examples
Here’s the basic import setup:
from multiprocessing import Process, Value, RawValue, Array, RawArray
import ctypes
import time
Now that we’re ready, let’s start sharing.
Using Value
: Sharing a Single Number Between Processes
Sometimes, we want to share just one number between two or more processes—like a counter, a flag, or a score. In this example, imagine a rabbit running a race. One process will update the rabbit’s speed, while the main process checks how fast it’s going. Python’s multiprocessing
module has a tool called Value
that lets you do this. It works with ctypes
types like c_int
or c_float
, so you can share basic numbers like integers and floats. Here’s how we can use it to track the rabbit’s speed:
from multiprocessing import Process, Value
import ctypes
import time
def speed_up(speed):
print("Rabbit starts running...")
time.sleep(1)
speed.value = 12.5
print("Rabbit reached 12.5 m/s!")
if __name__ == "__main__":
rabbit_speed = Value(ctypes.c_float, 0.0)
p = Process(target=speed_up, args=(rabbit_speed,))
p.start()
p.join()
print(f"Main process sees rabbit speed: {rabbit_speed.value} m/s")
In this code, we create a shared Value
called rabbit_speed
with a starting value of 0.0
. Inside the child process, we set speed.value = 12.5
to simulate the rabbit speeding up. Then the main process reads and prints that updated speed. The key here is .value
, which lets us read and write to the shared number. It’s simple, safe, and perfect for when you need just one shared value.
Using RawValue
: Sharing Without a Lock
Sometimes, processes don’t need to take turns or worry about clashing when updating a shared value. Maybe the order doesn’t matter, or you’re just logging quick updates. In those cases, you can use RawValue
. It’s just like Value
, but it skips the safety lock, which means it’s faster—but also a bit more wild. To show this in action, let’s imagine two turtles going on a walk. Each one counts its steps and updates the shared number, but they don’t mind if their updates get mixed up now and then.
from multiprocessing import Process, RawValue
import ctypes
import time
def turtle_walk(name, steps, counter):
for i in range(steps):
counter.value += 1
print(f"{name} took step {i + 1}")
time.sleep(0.1)
if __name__ == "__main__":
step_counter = RawValue(ctypes.c_int, 0)
t1 = Process(target=turtle_walk, args=("Turtle A", 5, step_counter))
t2 = Process(target=turtle_walk, args=("Turtle B", 5, step_counter))
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Total steps recorded: {step_counter.value}")
In this example, RawValue
creates an integer shared by both turtles. Each turtle adds to the same .value
, and we don’t use any locks to control the order. That means the total might be correct, or it might not be, depending on timing. .value
still works exactly the same, but without the safety of a lock. Use this when you don’t care about perfect timing or precision—just quick updates from multiple processes.
Value vs RawValue
Both Value
and RawValue
let you share a single number between processes, and both use .value
to get or set the number. The main difference is:
Value
comes with a built-in lock. This means only one process can update the value at a time. It’s safe when you care about correct order or data accuracy.RawValue
has no lock. This means processes can update the value at the same time. It’s faster, but updates might get mixed up or lost if they overlap.
If you’re doing simple logging, counting, or don’t need exact results, RawValue
is fine. But if accuracy matters, use Value
.
Using Array
: Sharing a List Between Processes
Sometimes you need more than just one number—maybe a small list of values that multiple processes can work with. Python’s Array
lets you share a whole list between processes. Think of it like a list that lives in shared memory. You can read and write its items by index, just like a regular list. Let’s say we’re tracking birds landing on a tree. One process counts crows, the other counts parrots, and they each update their own spot in the list.
from multiprocessing import Process, Array
import ctypes
import time
def count_crows(tree):
for _ in range(3):
tree[0] += 1
print("Crow landed.")
time.sleep(0.2)
def count_parrots(tree):
for _ in range(5):
tree[1] += 1
print("Parrot landed.")
time.sleep(0.1)
if __name__ == "__main__":
bird_tree = Array(ctypes.c_int, [0, 0]) # Index 0 = crows, Index 1 = parrots
p1 = Process(target=count_crows, args=(bird_tree,))
p2 = Process(target=count_parrots, args=(bird_tree,))
p1.start()
p2.start()
p1.join()
p2.join()
print(f"Crows on tree: {bird_tree[0]}")
print(f"Parrots on tree: {bird_tree[1]}")
In this example, we use Array(ctypes.c_int, [0, 0])
to create a shared list with two counters: one for crows and one for parrots. Each process updates a different index in the array. Just like a regular list, you use square brackets (tree[0]
, tree[1]
) to read and write the values. The lock is built in, so updates won’t step on each other. This is great when you want to safely share and update multiple values between processes.
Using RawArray
: Faster Array Access Without Locks
Just like RawValue
, RawArray
gives you a shared list but without any locking. It’s faster, but there’s no protection if multiple processes try to update the same part at the same time. This makes it a good choice when each process works on its own section of the array. Let’s imagine a race track where each car’s position is stored in a shared array. Each process moves its own car forward during the race.
from multiprocessing import Process, RawArray
import ctypes
import time
def move_car(track, car_index):
for lap in range(5):
track[car_index] += 1
print(f"Car {car_index + 1} completed lap {lap + 1}")
time.sleep(0.1)
if __name__ == "__main__":
race_track = RawArray(ctypes.c_int, [0, 0, 0]) # 3 cars
p1 = Process(target=move_car, args=(race_track, 0))
p2 = Process(target=move_car, args=(race_track, 1))
p3 = Process(target=move_car, args=(race_track, 2))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
print("Final positions:")
print(f"Car 1: {race_track[0]} laps")
print(f"Car 2: {race_track[1]} laps")
print(f"Car 3: {race_track[2]} laps")
In this code, we use RawArray(ctypes.c_int, [0, 0, 0])
to make a list where each index holds a car’s lap count. Each process updates its own index, so there’s no fighting over data. The syntax is just like Array
, using index-based access (track[car_index]
). Since there’s no lock, it runs a bit faster, and works well when each process touches only its own part of the array.
Array vs RawArray
Both Array
and RawArray
let you share a list of values between processes using .[]
for reading and writing. The key difference is:
Array
includes a lock to keep things safe when multiple processes update the list at the same time. This helps avoid mixed-up data.RawArray
has no lock, so it’s faster but doesn’t protect against simultaneous changes. It works best when each process only changes its own part of the list.
If your processes might update the same items, use Array
. If each process handles separate parts and you want speed, RawArray
fits well.
Conclusion
In this article, you learned how to share data between Python processes using Value
, RawValue
, Array
, and RawArray
. These tools let you create shared numbers and lists that different processes can read and modify directly in memory. Whether you need safe, locked access with Value
and Array
, or faster, unlocked updates with RawValue
and RawArray
, Python’s multiprocessing.sharedctypes
has you covered for simple and effective inter-process communication.