| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 741070b commit fc549e3
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 8 | 8 | ## [unreleased][] | |
| 9 | 9 | ||
| 10 | 10 | ### Added | |
| 11 | + - Improved performance. String marshaling between python and clr now cached. | ||
| 12 | + Cache reduces GC pressure and saves from extensive memory copying. | ||
| 11 | 13 | - Added support for embedding python into dotnet core 2.0 (NetStandard 2.0) | |
| 12 | 14 | - Added new build system (pythonnet.15.sln) based on dotnetcore-sdk/xplat(crossplatform msbuild). | |
| 13 | 15 | Currently there two side-by-side build systems that produces the same output (net40) from the same sources. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,7 +18,7 @@ public object MarshalNativeToManaged(IntPtr pNativeData) | |||
| 18 | 18 | ||
| 19 | 19 | public abstract IntPtr MarshalManagedToNative(object managedObj); | |
| 20 | 20 | ||
| 21 | - public void CleanUpNativeData(IntPtr pNativeData) | ||
| 21 | + public virtual void CleanUpNativeData(IntPtr pNativeData) | ||
| 22 | 22 | { | |
| 23 | 23 | Marshal.FreeHGlobal(pNativeData); | |
| 24 | 24 | } | |
@@ -44,7 +44,12 @@ internal class UcsMarshaler : MarshalerBase | |||
| 44 | 44 | private static readonly MarshalerBase Instance = new UcsMarshaler(); | |
| 45 | 45 | private static readonly Encoding PyEncoding = Runtime.PyEncoding; | |
| 46 | 46 | ||
| 47 | - public override IntPtr MarshalManagedToNative(object managedObj) | ||
| 47 | + private const int MaxStringLength = 100; | ||
| 48 | + private const int MaxItemSize = 4 * (MaxStringLength + 1); | ||
| 49 | + private static readonly EncodedStringsFifoDictionary EncodedStringsDictionary = | ||
| 50 | + new EncodedStringsFifoDictionary(10000, MaxItemSize); | ||
| 51 | + | ||
| 52 | + public override unsafe IntPtr MarshalManagedToNative(object managedObj) | ||
| 48 | 53 | { | |
| 49 | 54 | var s = managedObj as string; | |
| 50 | 55 | ||
@@ -53,16 +58,36 @@ public override IntPtr MarshalManagedToNative(object managedObj) | |||
| 53 | 58 | return IntPtr.Zero; | |
| 54 | 59 | } | |
| 55 | 60 | ||
| 56 | - byte[] bStr = PyEncoding.GetBytes(s + "\0"); | ||
| 57 | - IntPtr mem = Marshal.AllocHGlobal(bStr.Length); | ||
| 58 | - try | ||
| 61 | + IntPtr mem; | ||
| 62 | + int stringBytesCount; | ||
| 63 | + if (s.Length <= MaxStringLength) | ||
| 59 | 64 | { | |
| 60 | - Marshal.Copy(bStr, 0, mem, bStr.Length); | ||
| 65 | + if (EncodedStringsDictionary.TryGetValue(s, out mem)) | ||
| 66 | + { | ||
| 67 | + return mem; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + stringBytesCount = PyEncoding.GetByteCount(s); | ||
| 71 | + mem = EncodedStringsDictionary.AddUnsafe(s); | ||
| 61 | 72 | } | |
| 62 | - catch (Exception) | ||
| 73 | + else | ||
| 63 | 74 | { | |
| 64 | - Marshal.FreeHGlobal(mem); | ||
| 65 | - throw; | ||
| 75 | + stringBytesCount = PyEncoding.GetByteCount(s); | ||
| 76 | + mem = Marshal.AllocHGlobal(stringBytesCount + 4); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + fixed (char* str = s) | ||
| 80 | + { | ||
| 81 | + try | ||
| 82 | + { | ||
| 83 | + PyEncoding.GetBytes(str, s.Length, (byte*)mem, stringBytesCount); | ||
| 84 | + } | ||
| 85 | + catch | ||
| 86 | + { | ||
| 87 | + // Do nothing with this. Very strange problem. | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + *(int*)(mem + stringBytesCount) = 0; | ||
| 66 | 91 | } | |
| 67 | 92 | ||
| 68 | 93 | return mem; | |
@@ -106,6 +131,14 @@ public static int GetUnicodeByteLength(IntPtr p) | |||
| 106 | 131 | } | |
| 107 | 132 | } | |
| 108 | 133 | ||
| 134 | + public override void CleanUpNativeData(IntPtr pNativeData) | ||
| 135 | + { | ||
| 136 | + if (!EncodedStringsDictionary.IsKnownPtr(pNativeData)) | ||
| 137 | + { | ||
| 138 | + base.CleanUpNativeData(pNativeData); | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 109 | 142 | /// <summary> | |
| 110 | 143 | /// Utility function for Marshaling Unicode on PY3 and AnsiStr on PY2. | |
| 111 | 144 | /// Use on functions whose Input signatures changed between PY2/PY3. | |
@@ -118,11 +151,29 @@ public static int GetUnicodeByteLength(IntPtr p) | |||
| 118 | 151 | /// <remarks> | |
| 119 | 152 | /// You MUST deallocate the IntPtr of the Return when done with it. | |
| 120 | 153 | /// </remarks> | |
| 121 | - public static IntPtr Py3UnicodePy2StringtoPtr(string s) | ||
| 154 | + public unsafe static IntPtr Py3UnicodePy2StringtoPtr(string s) | ||
| 122 | 155 | { | |
| 123 | - return Runtime.IsPython3 | ||
| 124 | - ? Instance.MarshalManagedToNative(s) | ||
| 125 | - : Marshal.StringToHGlobalAnsi(s); | ||
| 156 | + if (Runtime.IsPython3) | ||
| 157 | + { | ||
| 158 | + int stringBytesCount = PyEncoding.GetByteCount(s); | ||
| 159 | + IntPtr mem = Marshal.AllocHGlobal(stringBytesCount + 4); | ||
| 160 | + fixed (char* str = s) | ||
| 161 | + { | ||
| 162 | + try | ||
| 163 | + { | ||
| 164 | + PyEncoding.GetBytes(str, s.Length, (byte*)mem, stringBytesCount); | ||
| 165 | + } | ||
| 166 | + catch | ||
| 167 | + { | ||
| 168 | + // Do nothing with this. Very strange problem. | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + *(int*)(mem + stringBytesCount) = 0; | ||
| 172 | + } | ||
| 173 | + return mem; | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + return Marshal.StringToHGlobalAnsi(s); | ||
| 126 | 177 | } | |
| 127 | 178 | ||
| 128 | 179 | /// <summary> | |
@@ -208,7 +259,12 @@ internal class Utf8Marshaler : MarshalerBase | |||
| 208 | 259 | private static readonly MarshalerBase Instance = new Utf8Marshaler(); | |
| 209 | 260 | private static readonly Encoding PyEncoding = Encoding.UTF8; | |
| 210 | 261 | ||
| 211 | - public override IntPtr MarshalManagedToNative(object managedObj) | ||
| 262 | + private const int MaxStringLength = 100; | ||
| 263 | + | ||
| 264 | + private static readonly EncodedStringsFifoDictionary EncodedStringsDictionary = | ||
| 265 | + new EncodedStringsFifoDictionary(10000, 4 * (MaxStringLength + 1)); | ||
| 266 | + | ||
| 267 | + public override unsafe IntPtr MarshalManagedToNative(object managedObj) | ||
| 212 | 268 | { | |
| 213 | 269 | var s = managedObj as string; | |
| 214 | 270 | ||
@@ -217,21 +273,49 @@ public override IntPtr MarshalManagedToNative(object managedObj) | |||
| 217 | 273 | return IntPtr.Zero; | |
| 218 | 274 | } | |
| 219 | 275 | ||
| 220 | - byte[] bStr = PyEncoding.GetBytes(s + "\0"); | ||
| 221 | - IntPtr mem = Marshal.AllocHGlobal(bStr.Length); | ||
| 222 | - try | ||
| 276 | + IntPtr mem; | ||
| 277 | + int stringBytesCount; | ||
| 278 | + if (s.Length <= MaxStringLength) | ||
| 223 | 279 | { | |
| 224 | - Marshal.Copy(bStr, 0, mem, bStr.Length); | ||
| 280 | + if (EncodedStringsDictionary.TryGetValue(s, out mem)) | ||
| 281 | + { | ||
| 282 | + return mem; | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + stringBytesCount = PyEncoding.GetByteCount(s); | ||
| 286 | + mem = EncodedStringsDictionary.AddUnsafe(s); | ||
| 225 | 287 | } | |
| 226 | - catch (Exception) | ||
| 288 | + else | ||
| 227 | 289 | { | |
| 228 | - Marshal.FreeHGlobal(mem); | ||
| 229 | - throw; | ||
| 290 | + stringBytesCount = PyEncoding.GetByteCount(s); | ||
| 291 | + mem = Marshal.AllocHGlobal(stringBytesCount + 1); | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + fixed (char* str = s) | ||
| 295 | + { | ||
| 296 | + try | ||
| 297 | + { | ||
| 298 | + PyEncoding.GetBytes(str, s.Length, (byte*)mem, stringBytesCount); | ||
| 299 | + } | ||
| 300 | + catch | ||
| 301 | + { | ||
| 302 | + // Do nothing with this. Very strange problem. | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + ((byte*)mem)[stringBytesCount] = 0; | ||
| 230 | 306 | } | |
| 231 | 307 | ||
| 232 | 308 | return mem; | |
| 233 | 309 | } | |
| 234 | 310 | ||
| 311 | + public override void CleanUpNativeData(IntPtr pNativeData) | ||
| 312 | + { | ||
| 313 | + if (!EncodedStringsDictionary.IsKnownPtr(pNativeData)) | ||
| 314 | + { | ||
| 315 | + base.CleanUpNativeData(pNativeData); | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + | ||
| 235 | 319 | public static ICustomMarshaler GetInstance(string cookie) | |
| 236 | 320 | { | |
| 237 | 321 | return Instance; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments