Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
dynamo
Commits
c0e008b4
Commit
c0e008b4
authored
Feb 12, 2025
by
Ryan Olson
Committed by
GitHub
Feb 12, 2025
Browse files
fix: async access to gil updates; notes on perf (#159)
parent
c2a9636c
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
66 additions
and
39 deletions
+66
-39
runtime/rust/python-wheel/Cargo.lock
runtime/rust/python-wheel/Cargo.lock
+21
-21
runtime/rust/python-wheel/README.md
runtime/rust/python-wheel/README.md
+18
-0
runtime/rust/python-wheel/rust/engine.rs
runtime/rust/python-wheel/rust/engine.rs
+18
-10
runtime/rust/python-wheel/tests/soak.py
runtime/rust/python-wheel/tests/soak.py
+1
-1
runtime/rust/src/pipeline/network/egress/push.rs
runtime/rust/src/pipeline/network/egress/push.rs
+8
-7
No files found.
runtime/rust/python-wheel/Cargo.lock
View file @
c0e008b4
...
...
@@ -318,18 +318,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.
9
.0"
version = "1.
10
.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b
"
checksum = "
f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9
"
dependencies = [
"serde",
]
[[package]]
name = "cc"
version = "1.2.1
1
"
version = "1.2.1
3
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf
"
checksum = "
c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda
"
dependencies = [
"shlex",
]
...
...
@@ -348,9 +348,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "clap"
version = "4.5.2
7
"
version = "4.5.2
8
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796
"
checksum = "
3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff
"
dependencies = [
"clap_builder",
]
...
...
@@ -514,9 +514,9 @@ dependencies = [
[[package]]
name = "data-encoding"
version = "2.
7
.0"
version = "2.
8
.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f
"
checksum = "
575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010
"
[[package]]
name = "der"
...
...
@@ -1522,18 +1522,18 @@ dependencies = [
[[package]]
name = "pin-project"
version = "1.1.
8
"
version = "1.1.
9
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
1
e2e
c53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916
"
checksum = "
df
e2e
71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d
"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.
8
"
version = "1.1.
9
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb
"
checksum = "
f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67
"
dependencies = [
"proc-macro2",
"quote",
...
...
@@ -2459,9 +2459,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.
19
"
version = "0.8.
20
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e
"
checksum = "
cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148
"
dependencies = [
"serde",
"serde_spanned",
...
...
@@ -2480,9 +2480,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.2
3
"
version = "0.22.2
4
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee
"
checksum = "
17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474
"
dependencies = [
"indexmap 2.7.1",
"serde",
...
...
@@ -2749,11 +2749,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.1
2
.1"
version = "1.1
3
.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b
"
checksum = "
ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0
"
dependencies = [
"getrandom 0.
2
.1
5
",
"getrandom 0.
3
.1",
"serde",
]
...
...
@@ -2901,9 +2901,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.
0
"
version = "0.7.
2
"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "
7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419
"
checksum = "
59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603
"
dependencies = [
"memchr",
]
...
...
runtime/rust/python-wheel/README.md
View file @
c0e008b4
...
...
@@ -80,3 +80,21 @@ one server instance above, you should see the requests from the client being
distributed across the server instances in each server's output. If only one
server instance is started, you should see the requests go to that server
each time.
# Performance
The performance impacts of synchrononizing the Python and Rust async runtimes
is a critical consideration when optimizing the performance of a highly
concurrent and parallel distributed system.
The Python GIL is a global critical section and is ultimately the death of
parallelism. To compound that, when Rust async futures become ready,
accessing the GIL on those async event loop needs to be considered carefully.
Under high load, accessing the GIL or performing CPU intenstive tasks on
on the event loop threads can starve out other async tasks for CPU resources.
However, performing a
`tokio::task::spawn_blocking`
is not without overheads
as well.
If bouncing many small message back-and-forth between the Python and Rust
event loops where Rust requires GIL access, this is pattern where moving the
code from Python to Rust will give you significant gains.
runtime/rust/python-wheel/rust/engine.rs
View file @
c0e008b4
...
...
@@ -13,6 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use
std
::
sync
::
Arc
;
pub
use
serde
::{
Deserialize
,
Serialize
};
pub
use
triton_distributed
::{
error
,
...
...
@@ -86,8 +88,8 @@ enum ResponseProcessingError {
#[pyclass]
#[derive(Clone)]
pub
struct
PythonAsyncEngine
{
generator
:
PyObject
,
event_loop
:
PyObject
,
generator
:
Arc
<
PyObject
>
,
event_loop
:
Arc
<
PyObject
>
,
}
#[pymethods]
...
...
@@ -105,8 +107,8 @@ impl PythonAsyncEngine {
#[new]
pub
fn
new
(
generator
:
PyObject
,
event_loop
:
PyObject
)
->
PyResult
<
Self
>
{
Ok
(
PythonAsyncEngine
{
generator
,
event_loop
,
generator
:
Arc
::
new
(
generator
)
,
event_loop
:
Arc
::
new
(
event_loop
)
,
})
}
}
...
...
@@ -130,12 +132,18 @@ where
// Create a channel to communicate between the Python thread and the Rust async context
let
(
tx
,
rx
)
=
mpsc
::
channel
::
<
Annotated
<
Resp
>>
(
128
);
let
stream
=
Python
::
with_gil
(|
py
|
{
let
generator
=
self
.generator
.clone
();
let
event_loop
=
self
.event_loop
.clone
();
let
stream
=
tokio
::
task
::
spawn_blocking
(
move
||
{
Python
::
with_gil
(|
py
|
{
let
py_request
=
pythonize
(
py
,
&
request
)
?
;
let
gen
=
self
.
generator
.call1
(
py
,
(
py_request
,))
?
;
let
locals
=
TaskLocals
::
new
(
self
.
event_loop
.bind
(
py
)
.clone
());
let
gen
=
generator
.call1
(
py
,
(
py_request
,))
?
;
let
locals
=
TaskLocals
::
new
(
event_loop
.bind
(
py
)
.clone
());
pyo3_async_runtimes
::
tokio
::
into_stream_with_locals_v1
(
locals
,
gen
.into_bound
(
py
))
})
?
;
})
})
.await
??
;
let
stream
=
Box
::
pin
(
stream
);
...
...
runtime/rust/python-wheel/tests/soak.py
View file @
c0e008b4
...
...
@@ -55,7 +55,7 @@ async def client_init(runtime: DistributedRuntime, ns: str):
# Issue many concurrent requests to put load on the server,
# the task should issue the request and process the response
tasks
=
[]
for
i
in
range
(
1
0000
):
for
i
in
range
(
2
0000
):
tasks
.
append
(
asyncio
.
create_task
(
do_one
(
client
)))
await
asyncio
.
gather
(
*
tasks
)
...
...
runtime/rust/src/pipeline/network/egress/push.rs
View file @
c0e008b4
...
...
@@ -15,6 +15,7 @@
use
anyhow
::
Result
;
use
async_nats
::
client
::
Client
;
use
tracing
as
log
;
use
super
::
*
;
...
...
@@ -85,7 +86,7 @@ where
U
:
Data
+
for
<
'de
>
Deserialize
<
'de
>
,
{
async
fn
generate
(
&
self
,
request
:
SingleIn
<
AddressedRequest
<
T
>>
)
->
Result
<
ManyOut
<
U
>
,
Error
>
{
let
id
=
request
.context
()
.id
()
.to_string
();
let
request_
id
=
request
.context
()
.id
()
.to_string
();
let
(
addressed_request
,
context
)
=
request
.transfer
(());
let
(
request
,
address
)
=
addressed_request
.into_parts
();
let
engine_ctx
=
context
.context
();
...
...
@@ -140,9 +141,9 @@ where
}
};
tracin
g
::
trace!
(
"[
req
: {}] packaging two-part message; ctrl: {} bytes, data: {} bytes"
,
id
,
lo
g
::
trace!
(
req
uest_id
,
"packaging two-part message; ctrl: {} bytes, data: {} bytes"
,
ctrl
.len
(),
data
.len
()
);
...
...
@@ -157,7 +158,7 @@ where
// TRANSPORT ABSTRACT REQUIRED - END HERE
tracin
g
::
trace!
(
"[
req
: {}]
enqueueing two-part message to nats"
,
id
);
lo
g
::
trace!
(
req
uest_id
,
"
enqueueing two-part message to nats"
);
// we might need to add a timeout on this if there is no subscriber to the subject; however, I think nats
// will handle this for us
...
...
@@ -166,7 +167,7 @@ where
.request
(
address
.to_string
(),
buffer
)
.await
?
;
tracin
g
::
trace!
(
"[
req
: {}]
awaiting transport handshake"
,
id
);
lo
g
::
trace!
(
req
uest_id
,
"
awaiting transport handshake"
);
let
response_stream
=
response_stream_provider
.await
.map_err
(|
_
|
PipelineError
::
DetatchedStreamReceiver
)
?
...
...
@@ -179,7 +180,7 @@ where
Ok
(
r
)
=>
Some
(
r
),
Err
(
err
)
=>
{
let
json_str
=
String
::
from_utf8_lossy
(
&
msg
);
tracing
::
error
!
(
%
err
,
%
json_str
,
"Failed deserializing JSON to response"
);
log
::
warn
!
(
%
err
,
%
json_str
,
"Failed deserializing JSON to response"
);
None
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment