Python学习笔记(二十):

  1. socketserver
  2. 多线程

1. SocketServer

  • 利用socketserver模块实现多线程
import socketserver

class MyServer(socketserver.BaseRequestHandler):

    def handle(self):
        print('服务器启动...')
        while True:
            conn = self.request
            print(self.client_address)
            while True:
                client_data = conn.recv(1024)
                print(str(client_data, 'utf8'))
                print('waiting...')
                server_response = input('>>:')
                conn.sendall(bytes(server_response, 'utf8'))
            conn.close


if __name__ == '__main__':
    # 创建链接
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 8091), MyServer)
    # 
    server.serve_forever()

2. 多线程

1. 线程

  • 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务
  • 线程是执行上下文,它是CPU执行指令流所需的全部信息。
  • 假设你正在读一本书,现在你想休息一下,但你希望能够回来,从你停下来的确切地点恢复阅读。一个实现的方法就是记下页码,行数和字数。所以你阅读书的执行上下文是这3个数字。
  • 如果你有一个室友,而且她使用相同的技巧,她可以在你不使用的时候拿书,然后从她停止阅读的地方继续阅读。然后你可以收回它,从你原来的地方恢复它。
  • 线程以同样的方式工作。CPU给了你一个错觉,那就是它在同时进行多个运算。它通过在每个计算上花费一点时间来实现这一点。它可以这样做,因为它为每个计算都有一个执行上下文。就像你可以和朋友共享一本书一样,许多任务可以共享一个CPU。
  • 在更高的技术层面上,执行上下文(因此线程)由CPU寄存器的值组成。
  • 最后:线程不同于进程。线程是执行的上下文,而进程是与计算相关联的一堆资源。一个进程可以有一个或多个线程。
  • 说明:与进程相关的资源包括内存页(进程中的所有线程对内存具有相同的视图)、文件描述符(例如,打开套接字)和安全凭据(例如启动进程的用户ID)。

2. 进程

  • 程序的执行实例称为进程。
  • 每个进程都提供执行程序所需的资源。一个进程有一个虚拟地址空间、可执行代码、对系统对象的开放句柄、一个安全上下文、一个独特的进程标识符、环境变量、一个优先级类、最小和最大工作集大小,以及至少一个执行线程。每个进程以一个线程开始,通常称为主线程,但可以从它的任何线程创建额外的线程。

3. 线程和进程的区别

  1. 线程共享创建它的进程的地址空间;进程有自己的地址空间。
  2. 线程直接访问进程的数据段;进程拥有父进程的数据段的自身副本。
  3. 线程可以直接与其他线程的过程;过程必须使用进程间通信与兄弟姐妹的过程。
  4. 很容易创建新线程;新进程需要重复父进程。
  5. 线程可以对相同进程的线程进行相当的控制;进程只能对子进程进行控制。
  6. 对主线程的更改(取消、优先级更改等)可能影响进程的其他线程的行为;对父进程的更改不会影响子进程。

4. 注意

  • 在Python里:如果任务是IO密集型的,可以用多线程;如果是计算密集型的,由于GIF锁的存在可以改用C。

5. join()

  • 在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

6. setDaemon()

  • 将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦

7. thread 模块提供的其他方法

# threading.currentThread(): 返回当前的线程变量。 
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。 
# 除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法: 
# run(): 用以表示线程活动的方法。 
# start():启动线程活动。 
# join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。 
# isAlive(): 返回线程是否活动的。 
# getName(): 返回线程名。 
# setName(): 设置线程名。