@@ -10,12 +10,19 @@ mod pyo3_runner;
1010#[ cfg( feature = "rustpython" ) ]
1111mod rustpython_runner;
1212
13+ use once_cell:: sync:: Lazy ;
1314use serde_json:: Value ;
1415use std:: path:: { Path , PathBuf } ;
1516use std:: thread;
1617use thiserror:: Error ;
18+ use tokio:: runtime:: Runtime ;
1719use tokio:: sync:: { mpsc, oneshot} ;
1820
21+ /// A lazily-initialized global Tokio runtime for synchronous functions.
22+ static SYNC_RUNTIME : Lazy < Runtime > = Lazy :: new ( || {
23+ Runtime :: new ( ) . expect ( "Failed to create a new Tokio runtime for sync functions" )
24+ } ) ;
25+
1926#[ derive( Debug ) ]
2027pub ( crate ) enum CmdType {
2128 RunFile ( PathBuf ) ,
@@ -143,9 +150,7 @@ impl PyRunner {
143150 ///
144151 /// **Note:** Calling this from an existing async runtime can lead to panics.
145152 pub fn run_sync ( & self , code : & str ) -> Result < ( ) , PyRunnerError > {
146- let rt =
147- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
148- rt. block_on ( self . run ( code) )
153+ SYNC_RUNTIME . block_on ( self . run ( code) )
149154 }
150155
151156 /// Asynchronously runs a python file.
@@ -166,9 +171,7 @@ impl PyRunner {
166171 ///
167172 /// **Note:** Calling this from an existing async runtime can lead to panics.
168173 pub fn run_file_sync ( & self , file : & Path ) -> Result < ( ) , PyRunnerError > {
169- let rt =
170- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
171- rt. block_on ( self . run_file ( file) )
174+ SYNC_RUNTIME . block_on ( self . run_file ( file) )
172175 }
173176
174177 /// Asynchronously evaluates a single Python expression.
@@ -190,9 +193,7 @@ impl PyRunner {
190193 ///
191194 /// **Note:** Calling this from an existing async runtime can lead to panics.
192195 pub fn eval_sync ( & self , code : & str ) -> Result < Value , PyRunnerError > {
193- let rt =
194- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
195- rt. block_on ( self . eval ( code) )
196+ SYNC_RUNTIME . block_on ( self . eval ( code) )
196197 }
197198
198199 /// Asynchronously reads a variable from the Python interpreter's global scope.
@@ -214,9 +215,7 @@ impl PyRunner {
214215 ///
215216 /// **Note:** Calling this from an existing async runtime can lead to panics.
216217 pub fn read_variable_sync ( & self , var_name : & str ) -> Result < Value , PyRunnerError > {
217- let rt =
218- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
219- rt. block_on ( self . read_variable ( var_name) )
218+ SYNC_RUNTIME . block_on ( self . read_variable ( var_name) )
220219 }
221220
222221 /// Asynchronously calls a Python function in the interpreter's global scope.
@@ -255,8 +254,7 @@ impl PyRunner {
255254 name : & str ,
256255 args : Vec < Value > ,
257256 ) -> Result < Value , PyRunnerError > {
258- let rt = tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
259- rt. block_on ( self . call_function ( name, args) )
257+ SYNC_RUNTIME . block_on ( self . call_function ( name, args) )
260258 }
261259
262260 /// Asynchronously calls an async Python function in the interpreter's global scope.
@@ -293,9 +291,7 @@ impl PyRunner {
293291 name : & str ,
294292 args : Vec < Value > ,
295293 ) -> Result < Value , PyRunnerError > {
296- let rt =
297- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
298- rt. block_on ( self . call_async_function ( name, args) )
294+ SYNC_RUNTIME . block_on ( self . call_async_function ( name, args) )
299295 }
300296
301297 /// Stops the Python execution thread gracefully.
@@ -312,9 +308,7 @@ impl PyRunner {
312308 ///
313309 /// **Note:** Calling this from an existing async runtime can lead to panics.
314310 pub fn stop_sync ( & self ) -> Result < ( ) , PyRunnerError > {
315- let rt =
316- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
317- rt. block_on ( self . stop ( ) )
311+ SYNC_RUNTIME . block_on ( self . stop ( ) )
318312 }
319313
320314 /// Set python venv environment folder (does not change interpreter)
@@ -360,9 +354,7 @@ impl PyRunner {
360354 ///
361355 /// **Note:** Calling this from an existing async runtime can lead to panics.
362356 pub fn set_venv_sync ( & self , venv_path : & Path ) -> Result < ( ) , PyRunnerError > {
363- let rt =
364- tokio:: runtime:: Runtime :: new ( ) . map_err ( |e| PyRunnerError :: PyError ( e. to_string ( ) ) ) ?;
365- rt. block_on ( self . set_venv ( venv_path) )
357+ SYNC_RUNTIME . block_on ( self . set_venv ( venv_path) )
366358 }
367359}
368360
0 commit comments