目录:
引言
一、线程
1.1 普通的多线程
1.2 自定义线程类
1.3 线程锁
1.3.1 未使用锁
1.3.2 普通锁Lock和RLock
1.3.3 信号量(Semaphore)
1.3.4 事件(Event)
1.3.5 条件(condition)
1.3 全局解释器锁(GIL)
1.4 定时器(Timer)
1.5 队列
1.5.1 Queue:先进先出队列
1.5.2 LifoQueue:后进先出队列
1.5.3 PriorityQueue:优先级队列
1.5.4 deque:双向队列
1.6 生产者消费者模型
1.7 线程池
二、进程
2.1 进程的数据共享
2.1.1 使用Array共享数据
2.1.2 使用Manager共享数据
2.1.3 使用queues的Queue类共享数据
2.2 进程锁
2.3 进程池
三、协程
3.1 greenlet
3.2 gevent
引言
解释器环境:python3.5.1
我们都知道python网络编程的两大必学模块socket和socketserver,其中的socketserver是一个支持IO多路复用和多线程、多进程的模块。一般我们在socketserver服务端代码中都会写这么一句:
server = socketserver.ThreadingTCPServer(settings.IP_PORT, MyServer)
ThreadingTCPServer这个类是一个支持多线程和TCP协议的socketserver,它的继承关系是这样的:
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
右边的TCPServer实际上是它主要的功能父类,而左边的ThreadingMixIn则是实现了多线程的类,它自己本身则没有任何代码。
MixIn在python的类命名中,很常见,一般被称为“混入”,戏称“乱入”,通常为了某种重要功能被子类继承。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class ThreadingMixIn: daemon_threads = False def process_request_thread(self, request, client_address): try: self.finish_request(request, client_address) self.shutdown_request(request) except: self.handle_error(request, client_address) self.shutdown_request(request) def process_request(self, request, client_address): t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start() |
在ThreadingMixIn类中,其实就定义了一个属性,两个方法。在process_request方法中实际调用的正是python内置的多线程模块threading。这个模块是python中所有多线程的基础,socketserver本质上也是利用了这个模块。
一、线程
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不独立拥有系统资源,但它可与同属一个进程的其它线程共享该进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个应用程序都至少有一个进程和一个线程。线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的被划分成一块一块的工作,称为多线程。
以上那一段,可以不用看!举个例子,厂家要生产某个产品,在它的生产基地建设了很多厂房,每个厂房内又有多条流水生产线。所有厂房配合将整个产品生产出来,某个厂房内的所有流水线将这个厂房负责的产品部分生产出来。每个厂房拥有自己的材料库,厂房内的生产线共享这些材料。而每一个厂家要实现生产必须拥有至少一个厂房一条生产线。那么这个厂家就是某个应用程序;每个厂房就是一个进程;每条生产线都是一个线程。
1.1 普通的多线程
在python中,threading模块提供线程的功能。通过它,我们可以轻易的在进程中创建多个线程。下面是个例子:
1 2 3 4 5 6 7 8 9 10 11 12 |
import threading import time def show(arg): time.sleep(1) print('thread'+str(arg)) for i in range(10): t = threading.Thread(target=show, args=(i,)) t.start() print('main thread stop') |
上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
下面是Thread类的主要方法:
- start 线程准备就绪,等待CPU调度
- setName 为线程设置名称
- getName 获取线程名称
- setDaemon 设置为后台线程或前台线程(默认是False,前台线程)
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止。如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止。 - join 该方法非常重要。它的存在是告诉主线程,必须在这个位置等待子线程执行完毕后,才继续进行主线程的后面的代码。但是当setDaemon为True时,join方法是无效的。
- run 线程被cpu调度后自动执行线程对象的run方法
1.2 自定义线程类
对于threading模块中的Thread类,本质上是执行了它的run方法。因此可以自定义线程类,让它继承Thread类,然后重写run方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import threading class MyThreading(threading.Thread): def __init__(self,func,arg): super(MyThreading,self).__init__() self.func = func self.arg = arg def run(self): self.func(self.arg) def f1(args): print(args) obj = MyThreading(f1, 123) obj.start() |
1.3 线程锁
CPU执行任务时,在线程之间是进行随机调度的,并且每个线程可能只执行n条代码后就转而执行另外一条线程。由于在一个进程中的多个线程之间是共享资源和数据的,这就容易造成资源抢夺或脏数据,于是就有了锁的概念,限制某一时刻只有一个线程能访问某个指定的数据。
1.3.1 未使用锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time (Semaphore) 1.3.4 事件(Event) 1.3.5 条件(condition) 1.3 全局解释器锁(GIL) 1.4 定时器(Timer) 1.5 队列 1.5.1 Queue:先进先出队列 1.5.2 LifoQueue:后进先出队列 1.5.3 PriorityQueue:优先级队列 1.5.4 deque:双向队列 1.6 生产者消费者模型 1.7 线程池 二、进程2.1 进程的数据共享 三、协程3.1 greenlet 引言解释器环境:python3.5.1
在ThreadingMixIn类中,其实就定义了一个属性,两个方法。在process_request方法中实际调用的正是python内置的多线程模块threading。这个模块是python中所有多线程的基础,socketserver本质上也是利用了这个模块。 一、线程线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不独立拥有系统资源,但它可与同属一个进程的其它线程共享该进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个应用程序都至少有一个进程和一个线程。线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的被划分成一块一块的工作,称为多线程。 1.1 普通的多线程在python中,threading模块提供线程的功能。通过它,我们可以轻易的在进程中创建多个线程。下面是个例子:
上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
1.2 自定义线程类对于threading模块中的Thread类,本质上是执行了它的run方法。因此可以自定义线程类,让它继承Thread类,然后重写run方法。
1.3 线程锁CPU执行任务时,在线程之间是进行随机调度的,并且每个线程可能只执行n条代码后就转而执行另外一条线程。由于在一个进程中的多个线程之间是共享资源和数据的,这就容易造成资源抢夺或脏数据,于是就有了锁的概念,限制某一时刻只有一个线程能访问某个指定的数据。 1.3.1 未使用锁
|