python线程、进程和协程详解
|
引言 解释器环境:python3.5.1 我们都知道python网络编程的两大必学模块socket和socketserver,其中的socketserver是一个支持IO多路复用和多线程、多进程的模块。一般我们在socketserver服务端代码中都会写这么一句: server = socketserver.ThreadingTCPServer(settings.IP_PORT,MyServer)
右边的TCPServer实际上是它主要的功能父类,而左边的ThreadingMixIn则是实现了多线程的类,它自己本身则没有任何代码。 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,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模块提供线程的功能。通过它,我们可以轻易的在进程中创建多个线程。下面是个例子:
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调度 1.2 自定义线程类 对于threading模块中的Thread类,本质上是执行了它的run方法。因此可以自定义线程类,让它继承Thread类,然后重写run方法。 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 未使用锁
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time
NUM = 0
def show():
global NUM
NUM += 1
name = t.getName()
time.sleep(1) # 注意,这行语句的位置很重要,必须在NUM被修改后,否则观察不到脏数据的现象。
print(name,"执行完毕后,NUM的值为: ",NUM)
for i in range(10):
t = threading.Thread(target=show)
t.start()
print('main thread stop')
上述代码运行后,结果如下: main thread stop Thread-1 执行完毕后,NUM的值为: 10 Thread-2 执行完毕后,NUM的值为: 10 Thread-4 执行完毕后,NUM的值为: 10 Thread-9 执行完毕后,NUM的值为: 10 Thread-3 执行完毕后,NUM的值为: 10 Thread-6 执行完毕后,NUM的值为: 10 Thread-8 执行完毕后,NUM的值为: 10 Thread-7 执行完毕后,NUM的值为: 10 Thread-5 执行完毕后,NUM的值为: 10 Thread-10 执行完毕后,NUM的值为: 10 由此可见,由于线程同时访问一个数据,产生了错误的结果。为了解决这个问题,python在threading模块中定义了几种线程锁类,分别是:
1.3.2 普通锁Lock和RLock 类名:Lock或RLock 普通锁,也叫互斥锁,是独占的,同一时刻只有一个线程被放行。 import time import threading NUM = 10 def func(lock): global NUM lock.acquire() # 让锁开始起作用 NUM -= 1 time.sleep(1) print(NUM) lock.release() # 释放锁 lock = threading.Lock() # 实例化一个锁对象 for i in range(10): t = threading.Thread(target=func,args=(lock,)) # 记得把锁当作参数传递给func参数 t.start() 以上是threading模块的Lock类,它不支持嵌套锁。RLcok类的用法和Lock一模一样,但它支持嵌套,因此我们一般直接使用RLcok类。 1.3.3 信号量(Semaphore) 类名:BoundedSemaphore 这种锁允许一定数量的线程同时更改数据,它不是互斥锁。比如地铁安检,排队人很多,工作人员只允许一定数量的人进入安检区,其它的人继续排队。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
import threading
def run(n):
semaphore.acquire()
print("run the thread: %s" % n)
time.sleep(1)
semaphore.release()
num = 0
semaphore = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行
for i in range(20):
t = threading.Thread(target=run,))
t.start()
1.3.4 事件(Event) 类名:Event 事件主要提供了三个方法 set、wait、clear。
import threading
def func(e,i):
print(i)
e.wait() # 检测当前event是什么状态,如果是红灯,则阻塞,如果是绿灯则继续往下执行。默认是红灯。
print(i+100)
event = threading.Event()
for i in range(10):
t = threading.Thread(target=func,args=(event,i))
t.start()
event.clear() # 主动将状态设置为红灯
inp = input(">>>")
if inp == "1":
event.set() # 主动将状态设置为绿灯
1.3.5 条件(condition) 类名:Condition 该机制会使得线程等待,只有满足某条件时,才释放n个线程。
import threading
def condition():
ret = False
r = input(">>>")
if r == "yes":
ret = True
return ret
def func(conn,i):
print(i)
conn.acquire()
conn.wait_for(condition) # 这个方法接受一个函数的返回值
print(i+100)
conn.release()
c = threading.Condition()
for i in range(10):
t = threading.Thread(target=func,args=(c,i,))
t.start()
(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
