一、基本概念
线程:进程中的每个子任务,不能独立存在
进程:独立的所有子任务的集合
线程,进程:目的都是想同时完成任务
特点:
进程的特点:独立(内存独立,cpu使用独立)启动进程开销大(速率低),进程之间很难共享数据,和数据通信,数据安全高。
线程的特点:依赖进程(内存共享,CPU使用独立)启动开销小,线程之间共享数据容易,方便通信,线程不安全。
二、两种方法
_thread threading(功能相比_thread更强大,推荐使用)
函数式:调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下
_thread.start_new_thread ( function, args[, kwargs] )
function - 线程函数 args - 传递给线程函数的参数,他必须是个tuple类型。 kwargs - 可选参数。
import _thread
import time
# 为线程定义一个函数
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print ("%s: %s" % ( threadName, time.ctime(time.time()) ))
# 创建两个线程
try:
_thread.start_new_thread( print_time, ("Thread-1", 2, ) )
_thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print ("Error: 无法启动线程")
while 1:
pass
二、使用类继承
1.继承threading.Thread
2.写构造方法,且必须调用父类的构造方法
3.重写父类的run方法,会在start之后自动调用
4.实现开始方法,如果重写了start()方法,一定要调用父类的start()
需要调用start()方法才可以执行
import time
import threading
class Mytherad(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self)
self.name = name
def run(self):
for i in range(5):
time.sleep(1)
print('你好!{}'.format(time.ctime(time.time()))+self.name)
s=Mytherad('s1')
t=Mytherad('t1')
s.start()
t.start()
三、线程的同步(上锁)
当多个线程同时进行任务时,为了保证不会有多个线程同时对同一个数据进行操作造成不可预料的后果,所以有了锁的概念,我们通过锁来使多线程任务更加安全。
锁当然有锁定和未锁定两种状态,当一个线程要访问共享数据时,必须要先获得锁定,如果已经有别的线程获得锁定,那么就进入暂停状态,等别的线程把锁释放后,再进行操作
threadLock = threading.Lock()
Condition:更精确的控制锁,提供了四个方法,上锁(acquire()),等待(wait()),解锁(release()),唤醒(notify(),notify_all())
lock=threading.lock()
cond=threading.Condition(lock=lock)
import threading,time
#生产者锁:伙夫
lock1=threading.Lock()
cond1=threading.Condition(lock=lock1)
#消费者锁:和尚
lock2=threading.Lock()
cond2=threading.Condition(lock=lock2)
#生产的馒头
mantou=[]
#生产者类
class Huofu(threading.Thread):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
while True:
cond2.acquire()#消费者上锁、只许一个人进来
for i in range(1,11):
time.sleep(1)
mantou.append(i)
print(i)
cond2.notify_all()
cond2.release()
cond1.acquire()
cond1.wait()
cond1.release()
class Heshang(threading.Thread):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
while True:
cond2.acquire()#消费者上锁、只许一个人进来
eat = None
if len(mantou)==0:
cond1.acquire()
cond1.notify()#通知生产者生产
cond1.release()
cond2.wait()
else:
eat=mantou.pop()
time.sleep(1)
cond2.release()
if eat != None:
print(self.name, '正在吃:', eat)
huofu=Huofu('伙夫')
heshang=Heshang('花和尚')
heshang1=Heshang('唐和尚')
heshang2=Heshang('酸和尚')
huofu.start()
heshang.start()
heshang1.start()
heshang2.start()
三、线程方法
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
run(): 用以表示线程活动的方法。
start():启动线程活动。
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。