<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=LessPythonInvoke</id>
	<title>LessPythonInvoke - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=LessPythonInvoke"/>
	<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=LessPythonInvoke&amp;action=history"/>
	<updated>2026-04-15T17:34:17Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=LessPythonInvoke&amp;diff=971&amp;oldid=prev</id>
		<title>Artheru：​创建页面，内容为“ = LessPython C# &amp;#x3C;-&amp;#x3E; Python Interop = A high-performance, cross-platform interop layer between C# and Python using shared memory (MMF) for data transfer and a lightweight TCP notify channel. Optimized for large &lt;code&gt;NumPy&lt;/code&gt; arrays via a compact binary protocol and zero-copy views.  == Quick start ==  # Ensure Python is available (optionally in a venv) and &lt;code&gt;numpy&lt;/code&gt; installed if you use array features. # Add this project to your solution…”</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=LessPythonInvoke&amp;diff=971&amp;oldid=prev"/>
		<updated>2025-09-04T08:51:23Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“ = LessPython C# &amp;lt;-&amp;gt; Python Interop = A high-performance, cross-platform interop layer between C# and Python using shared memory (MMF) for data transfer and a lightweight TCP notify channel. Optimized for large &amp;lt;code&amp;gt;NumPy&amp;lt;/code&amp;gt; arrays via a compact binary protocol and zero-copy views.  == Quick start ==  # Ensure Python is available (optionally in a venv) and &amp;lt;code&amp;gt;numpy&amp;lt;/code&amp;gt; installed if you use array features. # Add this project to your solution…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
= LessPython C# &amp;amp;#x3C;-&amp;amp;#x3E; Python Interop =&lt;br /&gt;
A high-performance, cross-platform interop layer between C# and Python using shared memory (MMF) for data transfer and a lightweight TCP notify channel. Optimized for large &amp;lt;code&amp;gt;NumPy&amp;lt;/code&amp;gt; arrays via a compact binary protocol and zero-copy views.&lt;br /&gt;
&lt;br /&gt;
== Quick start ==&lt;br /&gt;
&lt;br /&gt;
# Ensure Python is available (optionally in a venv) and &amp;lt;code&amp;gt;numpy&amp;lt;/code&amp;gt; installed if you use array features.&lt;br /&gt;
# Add this project to your solution or reference the produced DLL.&lt;br /&gt;
# Write a Python module with functions to call from C#.&lt;br /&gt;
# Initialize and call via a typed interface:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;# exporting_module.py:&lt;br /&gt;
def add_ints(a, b):&lt;br /&gt;
    return int(a) + int(b)&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;public interface IMyPyApi&lt;br /&gt;
{&lt;br /&gt;
    [PythonImport] int add_ints(int a, int b);&lt;br /&gt;
    [PythonImport] NdArray inc_ndarray(NdArray nd);&lt;br /&gt;
    [PythonImport(&amp;quot;inc_ndarray_timed&amp;quot;)] (NdArray, double) inc_ndarray_timed(NdArray nd);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var api = LessPythonInvoke.Initialize&amp;lt;IMyPyApi&amp;gt;(&lt;br /&gt;
    pythonVenvPath: &amp;quot;&amp;quot;,                 // optional venv root (&amp;quot;&amp;quot; =&amp;gt; system python)&lt;br /&gt;
    exportingPyPath: &amp;quot;lesspy_work/exporting_module.py&amp;quot;, // your module path&lt;br /&gt;
    debug: false,&lt;br /&gt;
    keepAlive: true,&lt;br /&gt;
    capacity: 256 * 1024 * 1024          // per-file MMF capacity&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int x = api.add_ints(2, 40);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&amp;lt;code&amp;gt;LessPythonInvoke.Initialize&amp;amp;#x3C;T&amp;amp;#x3E;(string pythonVenvPath, string exportingPyPath, bool debug=false, bool keepAlive=false, int capacity=16*1024*1024)&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;pythonVenvPath&amp;lt;/code&amp;gt;: optional; empty string uses system &amp;lt;code&amp;gt;python&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;python3&amp;lt;/code&amp;gt;. - &amp;lt;code&amp;gt;exportingPyPath&amp;lt;/code&amp;gt;: path to your Python module file. - &amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt;: enables extra logging from the shim. - &amp;lt;code&amp;gt;keepAlive&amp;lt;/code&amp;gt;: keep Python server and MMFs running across C# process runs. - &amp;lt;code&amp;gt;capacity&amp;lt;/code&amp;gt;: size of each MMF file (request/response). Must be large enough for your largest payload.&lt;br /&gt;
&lt;br /&gt;
MMF/aux files are placed under &amp;lt;code&amp;gt;bin/&amp;amp;#x3C;config&amp;amp;#x3E;/&amp;amp;#x3C;tfm&amp;amp;#x3E;/lesspy_work/&amp;lt;/code&amp;gt;: - &amp;lt;code&amp;gt;req.mmf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;resp.mmf&amp;lt;/code&amp;gt;: shared memory files - &amp;lt;code&amp;gt;lesspy_shim.py&amp;lt;/code&amp;gt;: shim injected and launched - &amp;lt;code&amp;gt;python.pid&amp;lt;/code&amp;gt;: Python PID (keepalive) - &amp;lt;code&amp;gt;notify.port&amp;lt;/code&amp;gt;: TCP port (keepalive reconnect)&lt;br /&gt;
&lt;br /&gt;
== Attributes and binding ==&lt;br /&gt;
&lt;br /&gt;
* Mark interface methods with &amp;lt;code&amp;gt;[PythonImport]&amp;lt;/code&amp;gt;. The method name maps to the Python function name by default; override via &amp;lt;code&amp;gt;[PythonImport(&amp;amp;#x22;py_name&amp;amp;#x22;)]&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Supported argument/return types:&lt;br /&gt;
** &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;long&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;byte[]&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;int[]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int[][]&amp;lt;/code&amp;gt; (nested)&lt;br /&gt;
** &amp;lt;code&amp;gt;ValueTuple&amp;lt;/code&amp;gt; with supported element types&lt;br /&gt;
** &amp;lt;code&amp;gt;NdArray&amp;lt;/code&amp;gt; (NumPy) with shape/dtype/data&lt;br /&gt;
&lt;br /&gt;
== NdArray ==&lt;br /&gt;
&amp;lt;code&amp;gt;NdArray&amp;lt;/code&amp;gt; represents a NumPy array: &amp;lt;code&amp;gt;Shape&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Dtype&amp;lt;/code&amp;gt;, and data. On responses, if Python returns a NumPy array, the C# side returns an &amp;lt;code&amp;gt;NdArray&amp;lt;/code&amp;gt; backed by a zero-copy view over &amp;lt;code&amp;gt;resp.mmf&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;DataMemory&amp;lt;/code&amp;gt;). Accessing &amp;lt;code&amp;gt;NdArray.Data&amp;lt;/code&amp;gt; materializes a copy only on demand.&lt;br /&gt;
&lt;br /&gt;
== KeepAlive ==&lt;br /&gt;
&lt;br /&gt;
* When &amp;lt;code&amp;gt;keepAlive: true&amp;lt;/code&amp;gt;, the Python process keeps running after C# exits.&lt;br /&gt;
* On next run, C# will reuse the existing Python server by reading &amp;lt;code&amp;gt;python.pid&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;notify.port&amp;lt;/code&amp;gt;, then connect over TCP.&lt;br /&gt;
* If the notify connection drops, Python keeps listening; subsequent runs will reconnect.&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
* Binary protocol (no JSON) over SHM, single-byte notify via localhost TCP.&lt;br /&gt;
* Direct pointer copies for MMF read/write; no intermediate payload buffers on C# side.&lt;br /&gt;
* Zero-copy ndarray responses (views over &amp;lt;code&amp;gt;resp.mmf&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Example (4096x4096 float32 inc): ~24.9 ms end-to-end for one un-timed call (~5.1 GB/s raw read+write).&lt;br /&gt;
&lt;br /&gt;
Tips: - Use larger &amp;lt;code&amp;gt;capacity&amp;lt;/code&amp;gt; for big transfers. - Prefer returning arrays directly from Python for zero-copy on C#. - For transforms, compute into the response buffer on Python side to avoid extra copies.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* MMF locked on rapid restarts: you may see &amp;lt;code&amp;gt;user-mapped section open&amp;lt;/code&amp;gt;. Retry after a moment; add exponential backoff if needed.&lt;br /&gt;
* Type mismatch in tuples: ensure element types align (e.g., &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt;). The invoker coerces primitives where needed.&lt;br /&gt;
* KeepAlive not reusing: ensure &amp;lt;code&amp;gt;python.pid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;notify.port&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;req.mmf&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;resp.mmf&amp;lt;/code&amp;gt; remain present and Python is still running.&lt;br /&gt;
* Capacity exceeded: increase &amp;lt;code&amp;gt;capacity&amp;lt;/code&amp;gt; to fit your largest request/response.&lt;/div&gt;</summary>
		<author><name>Artheru</name></author>
	</entry>
</feed>