77using System . Reflection ;
88using System . Runtime . CompilerServices ;
99using System . Text . Json ;
10+ using System . Threading ;
1011using System . Threading . Tasks ;
1112using Python . Runtime ;
1213using PythonNETExtensions . Helpers ;
1617
1718namespace PythonNETExtensions . Core
1819{
20+ internal static class PythonInstance
21+ {
22+ private static int InstanceCount = 0 ;
23+
24+ public static void OnCreate ( )
25+ {
26+ if ( Interlocked . Increment ( ref InstanceCount ) == 1 )
27+ {
28+ return ;
29+ }
30+
31+ throw new Exception ( "There may only be 1 PythonCore instance!" ) ;
32+ }
33+ }
34+
1935 public class PythonCore < PyVersionT , PyConfigT >
2036 where PyVersionT : struct , IPythonVersion < PyVersionT >
2137 where PyConfigT : struct , IPythonConfig < PyConfigT >
2238 {
2339 public static readonly PythonCore < PyVersionT , PyConfigT > INSTANCE = new PythonCore < PyVersionT , PyConfigT > ( ) ;
2440
41+ static PythonCore ( )
42+ {
43+ PythonInstance . OnCreate ( ) ;
44+ }
45+
2546 private PythonCore ( ) { }
2647
2748 private static readonly HttpClient HTTP_CLIENT = new HttpClient ( ) ;
49+
50+ private enum InitializationState : int
51+ {
52+ Uninitialized = 0 ,
53+ Initialized = - 1
54+ }
55+
56+ private static int IsInitialized = ( int ) InitializationState . Uninitialized ;
57+
58+ private static bool TryInitialize ( )
59+ {
60+ var oldVal = ( InitializationState ) Interlocked . CompareExchange ( ref IsInitialized , ( int ) InitializationState . Initialized , ( int ) InitializationState . Uninitialized ) ;
61+
62+ return oldVal == InitializationState . Uninitialized ;
63+ }
2864
2965 public Task InitializeAsync ( )
3066 {
@@ -36,6 +72,8 @@ public Task InitializeAsync()
3672 [ MethodImpl ( MethodImplOptions . AggressiveInlining | MethodImplOptions . AggressiveOptimization ) ]
3773 private static async Task InitializeAsyncInternal ( )
3874 {
75+ TryInitialize ( ) ;
76+
3977 var pythonBundleDirectory = PyConfigT . PythonHomePath ;
4078
4179 if ( Directory . Exists ( pythonBundleDirectory ) )
@@ -97,6 +135,11 @@ public Task InitializeDependentPackages()
97135 [ MethodImpl ( MethodImplOptions . AggressiveInlining | MethodImplOptions . AggressiveOptimization ) ]
98136 private static async Task InitializeDependentPackagesInternal ( )
99137 {
138+ if ( ( InitializationState ) IsInitialized == InitializationState . Uninitialized )
139+ {
140+ throw new Exception ( $ "Please run { nameof ( InitializeAsync ) } () first!") ;
141+ }
142+
100143 // Apparently this causes stackoverflow when PythonExtensions.GetCachedPythonModule<>() is invoked...
101144 // // TODO: Consider asynchronous awaiting of pip process
102145 // await Task.Yield();
0 commit comments