Python 10th Day

列表推导式 (list comprehension)

格式:[thing for thing in list_of_things]

for 左边是会添加到列表中的内容,比如:

def list_doubler(lst):
    return [num * 2 for num in lst]

等于

def list_doubler(lst):
    doubled = []
    for num in lst:
        doubled.append(num*2)
    return doubled

所以,下面这个例子中的返回值是一个由 lambda 函数组成的列表,但是函数并没有被执行。

li = [lambda :x for x in range(10)]

当执行列表中的一个函数时,因为 for 循环最后 x 最后被赋值为 9, 所以执行 lambda 函数返回 9

ret = li[0]()

IO 多路复用 (I/O multiplexing)

select: Low-level I/O multiplexing module. It monitors sockets, open files, and pipes (anything with a fileno() method that returns a valid file descriptor) until they become readable or writable, or a communication error occurs. select() makes it easier to monitor multiple connections at the same time, and is more efficient than writing a polling loop in Python using socket timeouts, because the monitoring happens in the operating system network layer, instead of the interpreter.

Classes hierarchy:

BaseSelector
+-- SelectSelector
+-- PollSelector
+-- EpollSelector
+-- DevpollSelector
+-- KqueueSelector

BaseSelector:

  • A BaseSelector is used to wait for I/O event readiness on multiple file objects
  • It’s an abstract base class, so cannot be instantiated

下面我们主要介绍 select.select 方法,这个方法可以直接调用 POSIX (both of Unix and Windows) function select(), three lists containing communication channels to monitor: 

select.select(rlist, wlist, xlist[, timeout]),

  • rlist: a list of the objects to be checked for incoming data to be read
  • wlist: contains objects that will receive outgoing data when there is room in their buffer
  • xlist: wait for an “exceptional condition”

 简单来说 rlist, wlist, xlist 分别用来监听 read events, write events 以及 error events.

示例程序:

#!/usr/bin/env python

import socket
import select

# create server side socket obj that serving for new connection
sk_obj = socket.socket()
sk_obj.bind(('127.0.0.1', 3000,))
sk_obj.listen(5)

inputs = [sk_obj,]
outputs = []
message = {}

while True:
    # rlist has elem when accept new connection
    '''
    select() returns three new lists, containing subsets of the contents of the lists passed in
    All of the sockets in the [rlist] list have incoming data buffered and available to be read
    All of the sockets in the [wlist] list have free space in their buffer and can be written to
    The sockets returned in [elist] have had an error
    '''
    rlist,wlist,elist, = select.select(inputs, outputs, inputs, 1)
    # print(len(inputs), len(rlist), len(outputs), len(wlist))
    '''
    监听 sk_obj 对象, 如果有新连接, select.select 函数返回的 rlist 为 [sk_obj,]
    监听 conn 对象, 如果 conn 变化, 表示客户端发送新消息, 此时 rlist 的值为发送消息的客户端
    rlist 中可能有 sk_obj 或者 conn
    如果是 sk_obj 说明有新连接, 那么把为这个新连接创建的 conn 添加进 rlist
    如果是 conn 说明客户端有发送数据, 那么把 conn 添加进 wlist
    '''
    # iterate the readable sockets
    for r in rlist:
        '''
        If the socket is the main “server” socket (sk_obj), the one being used to listen for connections,
        then the “readable” condition means it is ready to accept another incoming connection
        '''
        if r is sk_obj:
            conn, addr = r.accept()
            '''
            adding the new connection to the list of inputs to monitor
            this section sets the client socket to not block: conn.setblocking(0)
            '''
            inputs.append(conn)
            message[conn] = []
            conn.sendall("hello".encode(encoding='utf-8'))
        # for established connection with a client has sent data
        else:
            try:
                # conn.recv
                data = r.recv(1024)
                # A readable client socket has data
                if data:
                    # Add output channel for response
                    outputs.append(r)
                    message[r].append(data)
                # A readable socket without data available is from a client that has disconnected,
                # and the stream is ready to be closed
                else:
                    inputs.remove(r)
                    r.close()
                    del message[r]
                    # raise Exception('close connection')
            # Stop listening for input on the connection
            except Exception as e:
                inputs.remove(r)
                r.close()
                del message[r]

    for w in wlist:
        msg = message[w].pop()
        response = msg + 'response'.encode(encoding='utf-8')
        w.sendall(response)
        outputs.remove(w)

    for e in elist:
        inputs.remove(r)
        r.close()
        del message[r]

 

posted @ 2016-07-15 17:26  garyyang  阅读(174)  评论(0)    收藏  举报