mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
Create threading.md
This commit is contained in:
parent
cdbe55b539
commit
076627fb76
140
docs/features/threading.md
Normal file
140
docs/features/threading.md
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
icon: dot
|
||||||
|
title: Threading
|
||||||
|
---
|
||||||
|
|
||||||
|
pocketpy organizes its state by `VM` structure.
|
||||||
|
Users can have at maximum 16 `VM` instances (index from 0 to 15).
|
||||||
|
Each `VM` instance can only be accessed by exactly one thread at a time.
|
||||||
|
If you are trying to run two python scripts in parallel refering the same `VM` instance,
|
||||||
|
you will crash it definitely.
|
||||||
|
|
||||||
|
However, there are two ways to achieve multi-threading in pocketpy.
|
||||||
|
|
||||||
|
One way is to use a native threading library such as `pthread`.
|
||||||
|
You can wrap the multi-threading logic into a C function and bind it to pocketpy.
|
||||||
|
Be careful and not to access the same `VM` instance from multiple threads at the same time.
|
||||||
|
You need to lock critical resources or perform a deep copy of all needed data.
|
||||||
|
|
||||||
|
## ComputeThread
|
||||||
|
|
||||||
|
The other way is to use `pkpy.ComputeThread`.
|
||||||
|
It is like an isolate in Dart language.
|
||||||
|
`ComputeThread` is a true multi-threading model to allow you run python scripts in parallel without lock,
|
||||||
|
backed by a separate `VM` instance.
|
||||||
|
|
||||||
|
`ComputeThread` is highly designed for computational intensive tasks in games.
|
||||||
|
For example, you can run game logic in main thread (VM 0) and run world generation in another thread (e.g. VM 1).
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
subgraph Main Thread
|
||||||
|
A[Game Start]
|
||||||
|
B[Submit WorldGen Job]
|
||||||
|
C[Frame 1]
|
||||||
|
D[Frame 2]
|
||||||
|
E[Frame 3]
|
||||||
|
F[...]
|
||||||
|
G[Get WorldGen Result]
|
||||||
|
H[Render World]
|
||||||
|
end
|
||||||
|
subgraph WorldGen Thread
|
||||||
|
O[Generate Biomes]
|
||||||
|
P[Generate Terrain]
|
||||||
|
Q[Generate Creatures]
|
||||||
|
R[Dump Result]
|
||||||
|
end
|
||||||
|
A --> B
|
||||||
|
B --> C
|
||||||
|
C --> D
|
||||||
|
D --> E
|
||||||
|
E --> F
|
||||||
|
F --> G
|
||||||
|
G --> H
|
||||||
|
|
||||||
|
O --> P
|
||||||
|
P --> Q
|
||||||
|
Q --> R
|
||||||
|
|
||||||
|
B --> O
|
||||||
|
R --> G
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `main.py`
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
from pkpy import ComputeThread
|
||||||
|
|
||||||
|
thread = ComputeThread(1)
|
||||||
|
print("Game Start")
|
||||||
|
|
||||||
|
# import worldgen.py
|
||||||
|
thread.exec_blocked('from worldgen import gen_world')
|
||||||
|
|
||||||
|
print("Submit WorldGen Job")
|
||||||
|
thread.call('gen_world', 3, (100, 100), 10)
|
||||||
|
|
||||||
|
# wait for worldgen to finish
|
||||||
|
for i in range(1, 100000):
|
||||||
|
print('Frame:', i)
|
||||||
|
time.sleep(1)
|
||||||
|
if thread.is_done:
|
||||||
|
break
|
||||||
|
|
||||||
|
error = thread.last_error()
|
||||||
|
if error is not None:
|
||||||
|
print("Error:", error)
|
||||||
|
else:
|
||||||
|
retval = thread.last_retval()
|
||||||
|
biomes = retval['biomes']
|
||||||
|
terrain = retval['terrain']
|
||||||
|
creatures = retval['creatures']
|
||||||
|
print("World Generation Complete", len(biomes), len(terrain), len(creatures))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `worldgen.py`
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
def gen_world(biome_count: int, terrain_size: tuple[int, int], creature_count: int) -> dict:
|
||||||
|
# simulate a long computation
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
# generate world data
|
||||||
|
all_biomes = ["forest", "desert", "ocean", "mountain", "swamp"]
|
||||||
|
all_creatures = ["wolf", "bear", "fish", "bird", "lizard"]
|
||||||
|
|
||||||
|
width, height = terrain_size
|
||||||
|
|
||||||
|
terrain_data = [
|
||||||
|
random.randint(1, 10)
|
||||||
|
for _ in range(width * height)
|
||||||
|
]
|
||||||
|
|
||||||
|
creatures = [
|
||||||
|
{
|
||||||
|
"name": random.choice(all_creatures),
|
||||||
|
"x": random.randint(0, width - 1),
|
||||||
|
"y": random.randint(0, height - 1),
|
||||||
|
}
|
||||||
|
for i in range(creature_count)
|
||||||
|
]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"biomes": all_biomes[:biome_count],
|
||||||
|
"terrain": terrain_data,
|
||||||
|
"creatures": creatures,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `main.py` and you will see the result like this:
|
||||||
|
```
|
||||||
|
Game Start
|
||||||
|
Submit WorldGen Job
|
||||||
|
Frame: 1
|
||||||
|
Frame: 2
|
||||||
|
Frame: 3
|
||||||
|
Frame: 4
|
||||||
|
World Generation Complete 3 10000 10
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user