2013-04-12 5 views
11

저는 최근에 플라스크를 사용하여 파이썬 프로젝트에서 일하고 있습니다. pygments를 지원하는 서버 측 구문을 지원하는 간단한 pastebin입니다. 이것은 비용이 많이 드는 작업이기 때문에 구문 강조 표시를 샐러리 작업 대기열에 위임했으며 요청 처리기에서는 완료 될 때까지 기다리고 있습니다. 말할 필요도없이, 결과를 기다리는 것이 여전히 웹 서버에 대한 연결을 잠그기 때문에 다른 작업자에게 CPU 사용량을 줄이는 것만으로는 충분하지 않습니다. 전염병과 같은 조숙 한 최적화를 피하라고 내 본능에도 불구하고, 나는 여전히 비동기를 들여다 볼 수 없었습니다.파이썬 비동기 및 CPU 바인딩 작업?

비동기

최근 파이썬 웹 개발을 다음 한 경우, 당신은 분명히 그 비동기은 어디에나 보았다. 비동기는 협업 멀티 태스킹을 다시 가져오고 있습니다. 즉, 각 "스레드"가 언제 어디서 다른 인터페이스로 양보 할지를 결정합니다. 이 비 선점 프로세스는 OS 스레드보다 효율적이지만 여전히 단점이 있습니다.

  • 코 루틴
  • 첫 번째는 이벤트 루프에서 실행 느슨하게 결합 된 구성 요소를 통해 동시성을 제공하는 멀티 태스킹

    • 이벤트/콜백 스타일 : 순간이 주요 접근 방법이있을 것 같다. 이는 경쟁 조건과 관련하여 더 안전하고보다 일관성을 제공하지만 선점 형 멀티 태스킹에 비해 코드 작성이 훨씬 쉽지 않으며 어렵습니다.

      다른 하나는보다 전통적인 해결책이며 스레드 프로그래밍 스타일에 가깝고 프로그래머는 수동으로 컨텍스트를 전환해야합니다. 경쟁 조건 및 교착 상태가 더 많이 발생하기는하지만 쉽게 드롭 인 솔루션을 제공합니다.

      현재 대부분의 비동기 작업은 IO 바인딩 된 작업, 입력 또는 출력 대기를 차단하는 작업으로 수행됩니다. 이것은 보통 호출 할 수있는 폴링 및 타임 아웃 기반 함수의 사용을 통해 이루어지며 부정적으로 반환되면 컨텍스트를 전환 할 수 있습니다.

      이름에도 불구하고 이것은 CPU 바인딩 된 작업에도 적용될 수 있으며 다른 작업자 (스레드, 프로세스 등)에게 위임 된 다음 양보 할 수 있습니다. 이상적으로는 이러한 작업은 비동기식으로 작성되지만 현실적으로는 코드를 차단하지 않고 충분히 작은 청크로 분리하는 것을 의미합니다. 모든 코드 행마다 상황 전환 스위치가없는 것이 좋습니다. 이는 기존 동기 라이브러리에 특히 불편합니다.


      은 편의로 인해, 나는 비동기 작업 gevent를 사용하여 정착 CPU 바운드 비동기 환경에서 작업을 처리하는 방법 궁금 해서요 (선물, 셀러리 등을 사용하고 계십니까?).

      플라스크와 같은 전통적인 웹 프레임 워크에서 비동기 실행 모델 (이 경우에는 gevent)을 사용하는 방법은 무엇입니까? 파이썬 (future, task queues)에서 이러한 문제에 대해 공통적으로 합의한 해결책은 무엇입니까?

      편집 : 더 자세히 - 플라스크와 함께 gevent를 사용하는 방법과이 상황에서 CPU 바운드 작업을 처리하는 방법?

      EDIT2 : 파이썬에 스레드 코드의 최적 실행을 방해하는 GIL이있는 것을 고려하면 최소한 내 경우에는 다중 처리 옵션 만 남겨 둡니다.이것은 concurrent.futures 또는 처리를 다루는 다른 외부 서비스 (무언가 언어에 상관없이 문을 열 수 있음)를 사용하는 것을 의미합니다. 이 경우 gevent (, 즉 셀러리)와 함께 인기 있거나 자주 사용되는 솔루션은 무엇입니까? - 우수 사례

    +0

    이 패턴은 거의 모든 라이브러리에 적용 할 수 있습니다 (http://bottlepy.org/docs/dev/async.html#event-callbacks). 'concurrent.futures'의 수정 된 버전을 통합하여 장기간의 작업으로 협업 작업 (greenlets)을 결합 할 수 있기 때문에 나는 '상록수'를 제안합니다. – schlamar

    답변

    6

    는 비동기 스레드에 별도의 CPU를 많이 사용하는 작업에 다음과 같은 일을 할 스레드 안전해야 :

    from threading import Thread 
    
    def send_async_email(msg): 
        mail.send(msg) 
    
    def send_email(subject, sender, recipients, text_body, html_body): 
        msg = Message(subject, sender = sender, recipients = recipients) 
        msg.body = text_body 
        msg.html = html_body 
        thr = Thread(target = send_async_email, args = [msg]) 
        thr.start() 
    

    당신이 풀 "뭔가 더 복잡, 아마도 플라스크 - 셀러리 또는 멀티 라이브러리가 필요한 경우 "당신에게 유용 할 수 있습니다.

    나는 당신이 필요로하거나 더 복잡한 것이 무엇인지 상상할 수는 없지만 gevent에 너무 익숙하지 않다.

    중요한 세계 웹 사이트의 효율성을 얻으려고한다면 CPU 집약적 인 작업을 수행하도록 C++ 응용 프로그램을 작성한 다음 Flask-celery 또는 Pool을 사용하여 해당 프로세스를 실행하는 것이 좋습니다. (이것은 YouTube가 C++ & Python을 혼합 할 때 수행합니다.)

    +0

    Youtube가 (blogpost 또는 무언가) 어떻게 하는가에 대한 출처는 무엇입니까? – nikitautiu

    +0

    셀러리 사용이 끝났지 만, 내가 말했듯이, 결과를 기다리는 것은 웹 서버를 막는 결과를 가져옵니다. 해결 방법은 gevent 또는 geicorn 서버 중 하나를 사용하여 WSGI 응용 프로그램을 서버에 배치하는 것입니다. 비동기 결과의 경우 단순히'ready()'를 폴링하고 완료되지 않은 경우 정식'gevent.sleep() '을 사용하여 yield합니다. – nikitautiu

    +0

    나는 링크가 없지만 Google 블로그가 그것을 찾을 곳이 될지도 모르겠다. – Dexter

    1

    단순히 ThreadPool 및 Queue를 사용하는 것은 어떻습니까? 그런 다음 별도의 스레드에서 동기식으로 처리 할 수 ​​있으므로 전혀 차단하지 않아도됩니다. 글쎄, 파이썬은 처음에는 CPU 바운드 작업에 적합하지 않기 때문에 하위 프로세스를 생성하는 것도 고려해야합니다.

    +0

    그게 유효한 해결책이며, 제가 생각할 수있는 몇 가지 다른 것이 있습니다. 중요한 점은 gevent를 플라스크에 통합하는 방법을 궁금해했습니다. 그리고 gevent를 사용하는 사람들은 동기식 작업을 "녹색"으로 만드는 것이 불가능한 상황을 어떻게 처리합니까? – nikitautiu