파충류의 성능 최적화

34370 단어
문서 목록
  • 1.최적화 방향(막힘과 비막힘, 동기화, 비동기, 리셋)
  • 1.차단
  • 2.준비
  • 3.실행
  • 2.동기화 및 비동기식은 작업을 커밋하는 방법
  • 을 나타냅니다.
  • 1.동기화 호출
  • 1.1 솔루션(다중 스레드 또는 다중 프로세스)
  • 1.2 개선 방안(스레드 탱크와 프로세스 탱크 + 비동기 호출)
  • 2.비차단 IO(비동기 호출)
  • 1.asyncio 모듈
  • 2.asyncio+requests
  • 3.gevent 모듈(이동 제출 작업)
  • 4.grequests 모듈
  • 5.twisted
  • 6.tornado 모듈
  • 하나.최적화 방향(막힘과 비막힘, 동기화, 비동기, 리셋)
    ##1. 차단 및 비차단 응용 프로그램 상태
    request.get()
    1. 차단
    2.준비 완료
    준비와 차단이 사용자에게 주는 느낌은 바로 카드이다. 차단은 프로그램이io작업에 부딪혀 계속 실행할 수 없다는 것을 말한다
    3. 실행
    IO 조작에 있어서 다중 루트를 사용할 수도 있고 다중 프로세스를 사용할 수도 있다
    io 밀집형: 다중 루틴 계산 밀집형 사용 가능: 다중 프로세스를 사용해야 합니다
    둘.동기화 및 비동기는 작업을 커밋하는 방법을 나타냅니다.
    동기화: 작업을 제출한 후 제자리에서 기다리고 실행이 끝난 후에야 계속할 수 있는 비효율적인 것을 말한다
    비동기식: 작업을 제출한 후에는 상관하지 않고 계속 실행할 수 있어 효율이 높다
    1. 동시 호출
    import requests
    
    def parse_page(res):
        print('   %s' %(len(res)))
    
    def get_page(url):
        print('   %s' %url)
        response=requests.get(url)
        if response.status_code == 200:
            return response.text
    
    urls=['https://www.baidu.com/','http://www.sina.com.cn/','https://www.python.org']
    for url in urls:
        res=get_page(url) #      ,                      
        parse_page(res)
    

    1.1 솔루션(다중 스레드 또는 다중 프로세스)
    서버에서 다중 루틴이나 다중 프로세스를 사용할 때 모든 링크가 독립된 루틴(프로세스)을 가지도록 한다. 이렇게 하면 어떤 차단된 막힘도 다른 링크에 영향을 주지 않는다. (그러나 현장이 너무 많으면 서버에 대한 압력이 너무 크다)
    #IO           
    import requests
    from threading import Thread,current_thread
    
    def parse_page(res):
        print('%s    %s' %(current_thread().getName(),len(res)))
    
    def get_page(url,callback=parse_page):
        print('%s    %s' %(current_thread().getName(),url))
        response=requests.get(url)
        if response.status_code == 200:
            callback(response.text)
    
    if __name__ == '__main__':
        urls=['https://www.baidu.com/','http://www.sina.com.cn/','https://www.python.org']
        list = []
        for url in urls:
            t=Thread(target=get_page,args=(url,))
            t.start()
         	list.append(t)
        #                 
        for i in list:
    		i.join()
    

    1.2 개선 방안(스레드 탱크와 프로세스 탱크 + 비동기 호출)
    해결 방법: 프로세스 탱크 또는 스레드 탱크 + 리셋 메커니즘
    스레드 탱크: 스레드를 생성하고 소각하는 빈도를 줄이고 일정한 합리적인 수량의 스레드를 유지하며 빈 스레드로 하여금 새로운 실행 임무를 다시 맡게 한다
    링크 탱크: 링크의 캐시 탱크를 유지하고 기존의 연결을 최대한 다시 사용하며 링크를 만들고 닫는 빈도를 줄인다
    상기 두 가지 계수는 시스템의 비용을 잘 낮출 수 있어 모두 광범위하게 응용되었다
    import requests
    from threading import current_thread
    from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
    
    
    def parse_page(res):
        res = res.result()
        print('%s    %s' % (current_thread().getName(), len(res)))
    
    
    def get_page(url):
        print('%s    %s' % (current_thread().getName(), url))
        response = requests.get(url)
        if response.status_code == 200:
            return response.text
    
    
    if __name__ == '__main__':
        urls = [
            'https://www.baidu.com/', 'http://www.sina.com.cn/', 'https://www.python.org'
        ]
        pool = ThreadPoolExecutor(50)
    
        for url in urls:
            pool.submit(get_page, url).add_done_callback(parse_page)
    	#                  
        pool.shutdown(wait=True)
    
    

    향상된 문제점:
    스레드 탱크와 연결 탱크 기술도 Io의 빈번한 호출이 가져오는 호출 자원 문제를 어느 정도 완화시켰다. 요청한 수량이 스레드의 수량을 크게 초과할 때 스레드 탱크가 없는 것에 비해 큰 차이가 없기 때문에 응답 규모에 따라 스레드 탱크의 크기를 조정해야 한다.
    다중 스레드 모델은 소규모 서비스 요청을 편리하고 효율적으로 해결할 수 있지만 대규모 서비스 요청에 직면하면 다중 스레드 모델도 병목에 부딪힐 수 있다. 해결 방식은 비막힘io인터페이스를 사용하는 것이다.
    둘.비차단 IO(비동기 호출)
    **문제분석: **문제를 해결하는 관건은 우리가 응용 프로그램 단계에서 검사하는 것이다. 프로그램이 IO 조작을 만났을 때 우리는 프로그램의 다른 조작으로 전환한다. 그러면 cpu의 효율을 최대한 활용하고 프로그램의 Io를 최소화한다. 그러면 운영체제는 이 프로그램 전체의 Io가 비교적 적은 운영 프로그램으로 인정하고 cpu는 우리에게 최대한 분배한다.
    1.asyncio 모듈
    python 3.3 이후에 asyncio 모듈을 추가하여 IO를 자동으로 검출하고 응용 프로그램의 전환을 실현할 수 있습니다. 원리는gevent와 마찬가지로 IO를 만났을 때 하나의 작업(즉 협정)을 전환할 수 있습니다.
    자세히 보기:https://blog.csdn.net/qq_42737056/article/details/86645971
    import asyncio
    
    
    #        Io      
    @asyncio.coroutine
    def task(task_id, senconds):
        print('%s is start' % task_id)
        yield from asyncio.sleep(senconds)  # yield from    Io    ,       io       
        print('%s is end' % task_id)
    
    
    tasks = [task(task_id="  1", senconds=3), task("  2", 2), task(task_id="  3", senconds=1)]
    
    loop = asyncio.get_event_loop()
    #                  
    loop.run_until_complete(asyncio.wait(tasks))
    print('        ')
    loop.close()
    

    2.asyncio+requests
    asycio는 tcp 프로토콜의 요청만 발송할 수 있기 때문에 http 프로토콜의 요청 헤더는 스스로 헤더를 정의해야 하기 때문에 Requests와 분업하여 작업합니다
    import asyncio
    import requests
    
    
    def get_page(func, *args):
        print('GET: %s' % args[0])
        loop = asyncio.get_event_loop()
        future = loop.run_in_executor(None, func, *args)
        response = yield from future
    
        print(response.url, len(response.text))
        return ('complete')
    
    
    tasks = [
        get_page(requests.get, 'https://www.python.org/doc'),
        get_page(requests.get, 'https://www.cnblogs.com/linhaifeng'),
        get_page(requests.get, 'https://www.openstack.org')
    ]
    
    
    def run():
        loop = asyncio.get_event_loop()
        results = loop.run_until_complete(asyncio.gather(*tasks))
        loop.close()
        print('>>>', results)
    
    
    if __name__ == '__main__':
        run()
    
    

    3.gevent 모듈(이동 제출 작업)
    from gevent import monkey;monkey.patch_all()
    import gevent
    import requests
    
    def get_page(url):
        print('GET:%s' %url)
        response=requests.get(url)
        print(url,len(response.text))
        return 1
    
    #   
    from gevent.pool import Pool
    pool=Pool(2)
    g1=pool.spawn(get_page,'https://www.python.org/doc')
    g2=pool.spawn(get_page,'https://www.cnblogs.com/linhaifeng')
    g3=pool.spawn(get_page,'https://www.openstack.org')
    gevent.joinall([g1,g2,g3,])
    print(g1.value,g2.value,g3.value) #     
    

    4.grequests 모듈
    Request+gevent 모듈 봉인
    #pip3 install grequests
    import grequests
    
    request_list=[
        grequests.get('https://wwww.xxxx.org/doc1'),
        grequests.get('https://www.cnblogs.com/linhaifeng'),
        grequests.get('https://www.openstack.org')
    ]
    
    #          (    )
    def exception_handler(request, exception):
        # print(request,exception)
        print("%s Request failed" %request.url)
    
    #          
    response_list = grequests.map(request_list, exception_handler=exception_handler)
    print(response_list)
    

    5.twisted
    Twisted는 Python으로 이루어진 이벤트 구동 기반의 네트워크 엔진 프레임워크로 Twisted는 TCP, UDP, HTTP 등 많은 흔한 전송 및 응용층 프로토콜을 지원한다.
    python3에서 문자열은utf8 형식으로 변환해야 합니다. 그렇지 않으면 발송할 수 없습니다.예컨대 str("test").encode("utf8")면 된다
    from twisted.web.client import getPage, defer
    from twisted.internet import reactor
    
    
    def all_done(args):
        # print(args)
        reactor.stop()
    
    
    def callback(res):
        print(res)
        return 1
    
    
    defer_list = []
    urls = [
        'http://www.baidu.com',
        'http://www.bing.com',
        'https://www.python.org',
    ]
    for url in urls:
        obj = getPage(url.encode('utf-8'), )
        obj.addCallback(callback)
        defer_list.append(obj)
    defer.DeferredList(defer_list).addBoth(all_done)
    reactor.run()
    

    6.tornado 모듈
    Tornado는 Python을 사용하여 작성된 강력하고 확장 가능한 웹 서버입니다.그것은 심각한 네트워크 데이터를 처리할 때 충분히 강건하지만, 창설과 작성할 때 충분한 경량급을 가지고 있어 대량의 응용 프로그램과 도구에 사용될 수 있다.
    from tornado.httpclient import AsyncHTTPClient
    from tornado.httpclient import HTTPRequest
    from tornado import ioloop
    
    count=0
    
    def handle_response(response):
        """
               (       ,   IO  ),   ioloop.IOLoop.current().stop()
        :param response:
        :return:
        """
        if response.error:
            print("Error:", response.error)
        else:
            print(len(response.body))
    
        global count
        count-=1 #      ,   1
        if count == 0:
            ioloop.IOLoop.current().stop()
    
    def func():
        url_list = [
            'http://www.baidu.com',
            'http://www.bing.com',
        ]
    
        global count
        for url in url_list:
            print(url)
            http_client = AsyncHTTPClient()
            http_client.fetch(HTTPRequest(url), handle_response)
            count+=1 #   1
    
    ioloop.IOLoop.current().add_callback(func)
    ioloop.IOLoop.current().start()
    

    twisted와 tornado의 차이
    모두 파충류 기반의 서버 프레임워크(스킬 쓰기 서버, 쓰기 클라이언트가 있음)
    twisted: 성능은 강하지만 cpu에 대한 점용도 강합니다. tornado: 성능은 먼저 약하고 cpu에 대한 점용도 약합니다.

    좋은 웹페이지 즐겨찾기