Python學習---IO的非同步[自訂非同步IO]

來源:互聯網
上載者:User

標籤:tpc   描述符   www.   fun   lse   while   ==   start   width   

自訂IO非同步基礎知識:

      --所有的請求都基於socket實現,一個請求就是一個socket

        socket.setblocking(False) 不需要阻塞,一個請求完了發送另外一個,會報錯,需解決

      --IO多工[是同步的請求]

        IO多工有epoll, poll, select,知道epoll效能比其他幾者要好[epoll先找到門牌號然後找人]。

        IO多工本質上是在同一個線程或進程中,通過撥動開關的方式來執行多個IO操作。注意實際上每個IO操作都是獨立進行的。只是由原來的一對一變成了多對多。

        r,w,e = select.select([],[],[], 逾時時間)  # socket有請求/響應前面的r,w,e都會接收到的

IO非同步原理:

      IO非同步實現:本質則是【非阻塞Socket】+【IO多工】

IO非同步實現:本質則是【非阻塞Socket】+【IO多工】

import selectimport socketimport timeclass AsyncTimeoutException(TimeoutError):    """    請求逾時異常類    """    def __init__(self, msg):        self.msg = msg        super(AsyncTimeoutException, self).__init__(msg)# 封裝了socket和buffer的對象class HttpContext(object):    """封裝請求和相應的基本資料"""    def __init__(self, sock, host, port, method, url, data, callback, timeout=5):        """        sock: 請求的用戶端socket對象        host: 請求的主機名稱        port: 請求的連接埠        port: 請求的連接埠        method: 請求方式        url: 請求的URL        data: 請求時請求體中的資料        callback: 請求完成後的回呼函數        timeout: 請求的逾時時間        """        self.sock = sock        self.callback = callback        self.host = host        self.port = port        self.method = method        self.url = url        self.data = data        self.timeout = timeout        self.__start_time = time.time()        self.__buffer = []    def is_timeout(self):        """當前請求是否已經逾時"""        current_time = time.time()        if (self.__start_time + self.timeout) < current_time:            return True    def fileno(self):        """請求sockect對象的檔案描述符,用於select監聽"""        return self.sock.fileno()    def write(self, data):        """在buffer中寫入響應內容"""        self.__buffer.append(data)    def finish(self, exc=None):        """在buffer中寫入響應內容完成,執行請求的回呼函數"""        if not exc:            response = b‘‘.join(self.__buffer)            self.callback(self, response, exc)        else:            self.callback(self, None, exc)    def send_request_data(self):        content = """%s %s HTTP/1.0\r\nHost: %s\r\n\r\n%s""" % (            self.method.upper(), self.url, self.host, self.data,)        return content.encode(encoding=‘utf8‘)class AsyncRequest(object):    def __init__(self):        self.fds = []        self.connections = []    def add_request(self, host, port, method, url, data, callback, timeout):        """建立一個要請求"""        client = socket.socket()        client.setblocking(False)  # 不阻塞請求,不等待回應        try:            client.connect((host, port))        except BlockingIOError as e:            pass            # print(‘已經向遠程發送串連的請求‘)        req = HttpContext(client, host, port, method, url, data, callback, timeout)        self.connections.append(req)  # 封裝HttpContext對象        self.fds.append(req)    def check_conn_timeout(self):        """檢查所有的請求,是否有已經連線逾時,如果有則終止"""        timeout_list = []        for context in self.connections:            if context.is_timeout():                timeout_list.append(context)        for context in timeout_list:            context.finish(AsyncTimeoutException(‘請求逾時‘))            self.fds.remove(context)            self.connections.remove(context)    def running(self):        """事件迴圈,用於檢測請求的socket是否已經就緒,從而執行相關操作"""        while True:            r, w, e = select.select(self.fds, self.connections, self.fds, 0.05)            if not self.fds:                return            for context in r:                sock = context.sock                while True:                    try:                        data = sock.recv(8096)                        if not data:                            self.fds.remove(context)                            context.finish()                            break                        else:                            context.write(data)                    except BlockingIOError as e:                        break                    except TimeoutError as e:                        self.fds.remove(context)                        self.connections.remove(context)                        context.finish(e)                        break            for context in w:                # 已經串連成功遠程伺服器,開始向遠程發送請求資料                if context in self.fds:                    data = context.send_request_data()                    context.sock.sendall(data)                    self.connections.remove(context)            self.check_conn_timeout()if __name__ == ‘__main__‘:    def callback_func(context, response, ex):        """        :param context: HttpContext對象,內部封裝了請求相關資訊        :param response: 請求響應內容        :param ex: 是否出現異常(如果有異常則值為異常對象;否則值為None)        :return:        """        print(context, response, ex)    obj = AsyncRequest()    # 基於TCP構造HTTP    url_list = [        {‘host‘: ‘www.google.com‘, ‘port‘: 80, ‘method‘: ‘GET‘, ‘url‘: ‘/‘, ‘data‘: ‘‘, ‘timeout‘: 5,         ‘callback‘: callback_func},        {‘host‘: ‘www.baidu.com‘, ‘port‘: 80, ‘method‘: ‘GET‘, ‘url‘: ‘/‘, ‘data‘: ‘‘, ‘timeout‘: 5, ‘callback‘: callback_func},        {‘host‘: ‘www.bing.com‘, ‘port‘: 80, ‘method‘: ‘GET‘, ‘url‘: ‘/‘, ‘data‘: ‘‘, ‘timeout‘: 5, ‘callback‘: callback_func},    ]    for item in url_list:        print(item)        obj.add_request(**item)    obj.running()

Python學習---IO的非同步[自訂非同步IO]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.