본문 바로가기
Language/Python

python에 rusty를 섞는다?! 파이썬 segmentation fault 원인?

by 카프리썬 2021. 12. 3.
728x90

python + C

파이썬은 C와 C++을 이용해서 파이썬 함수를 작성하면 확장라이브러리를 만들 수 있다. 

네이티브 코드로 만든 파이썬함수는 일반 파이썬 모듈처럼 임포트한 뒤 바로 사용할 수 있다. 

 

그런데 굳이 C와 C++을 이용해서 파이썬 함수를 작성해야하나?

먼저, C와 C++ 라이브러리를 사용할때 필요하기 때문이다. 

C로 파이썬을 확장하게 되면 Qt같은 덩치큰 여러가지 라이브러리를 파이썬에서 사용할 수 있다.

다음으로, 파이썬은 인터프리터 언어이다보니 CPU에서 바로 실행될 수 있는 C보다 느리기 때문이다. 

그래서 많은 계산이 필요한 작업에선 적합하지 않다.

하지만 데이터분석과 같은 작업을 할때는 파이썬처럼 간단한 언어가 필수적인데, 

이럴때 계산부분은 C확장 프로그램에 맡기고, 알고리즘 작성하는 작업은 파이썬으로 진행하는 방식을 택하게 된다.

(그게 바로 Numpy나 Tensorflow같은 라이브러리가 동작하는 방식! 오 처음 알게 된 사실!) 

 

결국  C와 C++을 이용해서 파이썬 함수를 작성해서 확장라이브러리를 만드는 것이 가장 효율적이다. 

로직은 파이썬으로 구현하고, 계산은 C가 빠르게 실행할 수 있기 때문이다.

하지만, 정말 가장 좋을까? 파이썬은 메모리 관리를 자동으로 해주지만, C는 그렇지 않다. 

그래서 C로 파이썬 확장프로그램을 만들때 malloc()이나 free() 함수를 통해 직접 메모리를 할당/해제를 해줘야한다.

물론 확장라이브러리 안에서 사용하는 구조체에 한정되는 것으로

이후 파이썬코드에서 사용하는 객체를 쓸때 메모리를 할당하거나 해제할 경우 segmentation fault를 뱉을수도 있다. 

그래서 C가 파이썬인터프리터에 이 객체를 쓰고 있으니가 맘대로 할당하거나 해제하면 안된다고 해야한다. 

즉, 객체를 사용할때 파이썬 객체한테 레퍼런트 카운터 값을 1 증가시키고, 사용이 끝나면 1 감소시킨다.

그럼 파이썬은 레퍼런스카운트가 0일때 이 객체가 더이상 사용하지 않는 객체라는 것을 알 수 있게 된다. 

이 작업을 레퍼런스 카운팅 이라고 부르는데, 어디까지나 파이썬C구현체와 관련된 내용이다. 

 

결국, C로 파이썬 확장 라이브러리를 만들때 발생하는 문제는 아래와 같다. 

- C자체의 메모리안전성

- C에서 만든 객체를 파이썬에서 사용할때 메모리 할당/해제

- 파이썬에서 만든 객체를 C에서 사용할때의 레퍼런스 카운팅

그런데 이런 문제는 러스트의 차용검사(Borrow checking)기능으로 해결할 수 있다. 

메모리 안정성을 보장하는 필요불가결한 역할을 맡기 때문이다. 

 

러스트는 공동명의 라는개념이 존재하지 않는다고 한다.

사실 그 메모리의 공동명의 라는 개념 자체를 이해하기 어려웠는데.. 결론적으로 메모리를 참조하기보다 빌려쓴다..?

그래서 차용검사 기능 덕분에

일반적인 프로그래밍 상황에서 일어날 수 있는 메모리 사용오류를 미연에 전부 방지할 수 있어서

메모리 안전성을 보장할 수 잇있다고 한다. 

거기에 모든 변수가 언제 사라지는지 미리 알 수 있으니

파이썬 메모리 관리와 레퍼런스 카운팅같은 작업도 손쉽게 진행할 수 있다. 

즉, C로 파이썬 확장라이브러리를 만들때 발생하는 문제를 러스트로 해결할 수 있다는 것이다!

 

심지어 원문에서 진행한 퍼포먼스 테스트결과에 따르면 C와 러스트의 성능차이가 거의 없었다고 한다. 

그래서 결론적으로 파이썬 확장라이브러리를 만들게 된다면 C가 아니라 러스트를 가지고 만들어보는걸 추천! 

 

최근에 알수없는 이유로 파이썬에서 segmentation fault 에러 만난적 있었는데 그 이유가 내부적으로 C기반 라이브러리에서 메모리 할당문제 때문일수도 있었겠네요..! 러스트기반으로 되면 이러한 부분은 해결될수도 있다는점에서 유익했습니다.

 

원문은 이곳을 참고했습니다.

https://rangho.postype.com/post/6680526

반응형

$(document).ready(function() { var $toc = $("#toc"); $toc.toc({content: ".tt_article_useless_p_margin", headings: "h2,h3,h4"}); });