Doarchive

C# 에서 파이썬 코드 사용하기 PythonNet 설치 방법 및 환경세팅 (IronPython 과 Process방식과 비교) (1) 본문

ETC/Python

C# 에서 파이썬 코드 사용하기 PythonNet 설치 방법 및 환경세팅 (IronPython 과 Process방식과 비교) (1)

오순발닦개 2023. 6. 21. 14:10

 

C# 코드에서 파이썬 코드를 사용하거나 실행 할 일이 종종 생기는데  

이때 Python과 .NET Framework(C# 등)의 상호 운용성을 제공하는 패키지 를 사용해야 한다.   

대표적으로  IronPython ,Pythonnet, Process 방식으로 사용하는 방법이 있다.
세가지 방법에 대해 간단하게 설명하고  PythonNet 방식의 설정방법과 실행 방법을 공유하고자 한다 



IronPython

IronPython은 .NET 프레임워크 위에서 직접 실행되는 파이썬의 구현체.파이썬 코드를 CLR 객체로 변환하여 C#과 상호 작용할 수 있게 함


사용 상황: .NET 환경에서 파이썬 코드를 실행하거나, .NET 라이브러리에 접근해야 하는 파이썬 코드를 작성해야 하는 경우에 적합


장점: IronPython은 .NET 프레임워크의 모든 기능에 접근할 수 있음. 또한 C# 코드와 파이썬 코드 간에 강력한 상호 작용을 제공
단점: IronPython은 표준 파이썬(CPython)의 일부 기능이나 라이브러리를 지원하지 않을 수 있음. 또한 이것도   최신 버전의 파이썬을 원하지 않을 수 있음.  * 대표적으로 OpenCV를 지원하지 않음


IronPython 실행코드 , NuGet으로 설치해주면 바로 사용가능함 

 
 
   private void Iron_Btn_Click(object sender, EventArgs e) {
    var engine = global::IronPython.Hosting.Python.CreateEngine();
    var scope = engine.CreateScope();
    string scriptPath = @"C:\---path---utils.py";
    string imagePath = @"C:----path ---.bmp";

    try {
        var source = engine.CreateScriptSourceFromFile(scriptPath);
        source.Execute(scope);

        dynamic isClampLock = scope.GetVariable("is_clamp_lock");
        dynamic result = isClampLock(true, imagePath);

        Console.WriteLine(result);
    } catch (Exception ex) {
        Console.WriteLine(ex.Message);
    }
  }
 

 

 

 




Process 방식

이 방식은 C#에서 별도의 프로세스로 파이썬 스크립트를 실행하는 방법. 이 방식은 System.Diagnostics.Process 클래스를 사용하여 파이썬 인터프리터를 별도의 프로세스로 실행.
파이썬의 모든 라이브러리와 기능에 접근하고자 하거나, 파이썬 코드의 실행 환경을 C# 환경과 완전히 분리하고 싶은 경우에 적합 예를 들어, CPU 집중적인 작업을 동시에 실행하거나, 파이썬 스크립트가 실패하더라도 C# 애플리케이션에 영향을 주지 않게 하려면 이 방법을 사용할수 있다

장점: 이 방식은 CPython의 모든 기능과 라이브러리를 사용할 수 있음. 또한 이 방식은 독립적인 프로세스를 사용하기 때문에, 멀티프로세싱이 가능 이 방식은 C#과 파이썬 사이에 독립성을 유지하면서 둘을 통합할 수 있음.

단점: 프로세스 간 통신을 위해서는 IPC(Inter-Process Communication) 메커니즘을 사용해야 하며, 이는 일반적으로 Pythonnet이나 IronPython을 사용하는 것보다 느림.... 엄청 느림...... 

 

 

Process방식  실행코드 

 
 
 
  private void Process_Btn_Click(object sender, EventArgs e) {
    string pythonInterpreterPath = "C:\\Program Files\\Python311\\python.exe";
    string pythonScriptPath = "C:--path---.py";
    string imagePath = "C:--path---.bmp";
    string selectedFunction = "is_clamp_lock";

    ProcessStartInfo psi = new ProcessStartInfo {
        FileName = pythonInterpreterPath,
        Arguments = $"{pythonScriptPath} {selectedFunction} \"{imagePath}\"",
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardOutput = true
    };

    using (Process process = new Process { StartInfo = psi }) {
        process.Start();
        string output = process.StandardOutput.ReadToEnd();
        process.WaitForExit();
        Console.WriteLine(output);
    }
}
 
 
 

 


 

Pythonnet

Pythonnet은 C#에서 파이썬 코드를 호출할 수 있게 해주는 라이브러리. Pythonnet은 CLR(Common Language Runtime) 위에서 직접 실행되며, 파이썬 객체를 .NET 객체로 감싸서 서로 간에 호환성을 제공


사용 상황: C# 코드 내에서 파이썬 코드를 실행하거나 파이썬 객체를 사용해야 하는 경우에 적합


장점: 파이썬 코드와 C# 코드 사이의 직접적인 상호작용을 가능하게  이로 인해 두 언어 간의 데이터 전달이 빠르고 효율적.
단점: Pythonnet은 파이썬의 최신 버전을 항상 지원하지 않을 수 있음. 그리고 GIL(Global Interpreter Lock)로 인해 멀티스레딩이 제한될 수 있음.  -> 결론적으로 나는 이방법을 사용한다.

 

 

Pythonnet 방식 실행코드 

   
 
    public Form1()
        {
            InitializeComponent();

            Runtime.PythonDLL = @"C:/Program Files/Python39/python39.dll";
            PythonEngine.Initialize();

        }


        private void CartridgeCheckButton_Click(object sender, EventArgs e)
        {
           
            using (Py.GIL())
            {
                String m_pyProjectPath = "C:/Users/HJM/DoaOh/Project/FA_Vision";
                String m_pyClassPath = "vision_utils";
                string base_image = "C:/---path---.bmp";
                string compare_image = "C:/---path---.bmp";

                dynamic sys = Py.Import("sys");
                sys.path.append(m_pyProjectPath);
                dynamic visionUtils = Py.Import(m_pyClassPath);
                dynamic result = visionUtils.is_catridge_exist(base_image, compare_image);

                bool is_catridge_exist = result != null && result.As<bool>();
                Console.WriteLine("is_catridge_exist: " + is_catridge_exist);

            }
           

        }
 
 
 

 

 

사용 방법은 다음에.....

 
728x90