python3终止线程_python3 多线程编程

0.什么是线程

多线程模块

创建线程的方法

join()方法

4.isAlive()方法

name属性和daemon属性

6.线程的同步---锁

7.线程的同步---Event对象

8.线程的同步---Condition条件变量

0.什么是线程

线程是CPU分配资源的基本单位。但一个程序开始运行,这个程序就变成了一个进程,而一个进程相当于一个或者多个线程。当没有多线程编程时,一个进程也是一个主线程,但有多线程编程时,一个进程包含多个线程,包括主线程。使用线程可以实现程序的并发。

多线程模块

python3对多线程支持的是 threading 模块,应用这个模块可以创建多线程程序,并且在多线程间进行同步和通信。在python3 中,可以通过两种方法来创建线程:

第一:通过 threading.Thread 直接在线程中运行函数;第二:通过继承 threading.Thread 类来创建线程

创建线程的方法

1.用 thread.Thread 直接在线程中运行函数

[python] view plain copy

import threading

def threadfun(x,y): #线程任务函数 threadfun()

for i in range(x,y):

print(i)

ta = threading.Thread(target=threadfun,args=(1,6)) #创建一个线程ta,执行 threadfun()

tb = threading.Thread(target=threadfun,args=(10,15)) #创建一个线程tb,执行threadfun()

ta.start() #调用start(),运行线程

tb.start() #调用start(),运行线程

'''''打印:1 2 3 4 5 10 11 12 13 14'''

2.通过继承 thread.Thread 类 来创建线程

这种方法只需要重载 threading.Thread 类的 run 方法,然后调用 start()开启线程就可以了

[python] view plain copy

import threading

class mythread(threading.Thread):

def run(self):

for i in range(1,5):

print(i)

ma = mythread();

mb = mythread();

ma.start()

mb.start()

join()方法

join()作用是 调用 join() 的线程 阻塞直到 某一线程结束才继续执行

[python] view plain copy

import threading

import time

class mythread(threading.Thread):

def run(self):

self.i = 1

print('%d'%(self.i))

self.i = self.i+1

time.sleep(1) #睡眠一秒

print('%d'%(self.i))

time.sleep(1)

if __name__ == '__main__':

ta = mythread() #实例化线程

ta.start() #开启ta线程

ta.join() #主线程等待 ta线程结束才继续执行

print('main thread over')

4.isAlive()方法

这个方法用于判断线程是否运行。

1.当线程未调用 start()来开启时,isAlive()会返回False

2.但线程已经执行后并结束时,isAlive()也会返回False

[python] view plain copy

import threading

import time

class mythread(threading.Thread):

def run(self):

time.sleep(2)

if __name__ == '__main__':

ta = mythread() #实例化线程

print(ta.isAlive()) #打印False,因为未执行 start()来使ta线程运行

ta.start()

print(ta.isAlive()) #打印Ture,因为ta线程运行了

time.sleep(3)

print(ta.isAlive()) #打印False,因为ta线程已经结束了

name属性和daemon属性

1.name属性表示线程的线程名 默认是 Thread-x x是序号,由1开始,第一个创建的线程名字就是 Thread-1

[python] view plain copy

import threading

import time

class mythread(threading.Thread):

def run(self):

pass

if __name__ == '__main__':

ta = mythread() #实例化线程

ta.name = 'thread-ta'

tb = mythread()

tb.start()

ta.start()

print(ta.name) #打印 thread-ta

print(tb.name) #打印 Thread-2

2.daemon属性用来设置线程是否随主线程退出而退出

当 daemon = False 时,线程不会随主线程退出而退出(默认时,就是 daemon = False)

当 daemon = True 时,当主线程结束,其他子线程就会被强制结束

[python] view plain copy

import threading

import time

class mythread(threading.Thread):

def run(self):

time.sleep(2)

print('my thread over')

def main():

ta = mythread()

ta.daemon = True

ta.start()

print('main thread over')

if __name__ == '__main__':

main()

#打印结果 :main thread over 然后马上结束程序

6.线程的同步---锁

当一个进程拥有多个线程之后,如果他们各做各的任务互没有关系还行,但既然属于同一个进程,他们之间总是具有一定关系的。比如多个线程都要对某个数据进行修改,则可能会出现不可预料的结果。为保证操作正确,就需要引入锁来进行线程间的同步。

python3 中的 threading 模块提供了 RLock锁(可重入锁)。对于某一时间只能让一个线程操作的语句放到 RLock的acquire 方法 和 release方法之间。即 acquire()方法相当于给RLock 锁 上锁,而 release() 相当于解锁。

[python] view plain copy

import threading

import time

class mythread(threading.Thread):

def run(self):

global x #声明一个全局变量

lock.acquire() #上锁,acquire()和release()之间的语句一次只能有一个线程进入,其余线程在acquire()处等待

x += 10

print('%s:%d'%(self.name,x))

lock.release() #解锁

x = 0

lock = threading.RLock() #创建 可重入锁

def main():

l = []

for i in range(5):

l.append(mythread()) #创建 5 个线程,并把他们放到一个列表中

for i in l:

i.start() #开启列表中的所有线程

if __name__ =='__main__':

main()

打印结果:

Thread-1:10

Thread-2:20

Thread-3:30

Thread-4:40

Thread-5:50

7.线程的同步---Event对象

Event对象存在于 threading 模块中。Event 实例管理着 一个内部标志,通过 set() 方法来将该标志设置成 True,使用 clear() 方法将该标志重置成 False

wait() 方法会使当前线程阻塞直到标志被设置成 True,wait()可以选择给他一个参数,代表时间,代表阻塞多长时间,若不设置就是阻塞直到标志被设置为True

isSet()方法 :能判断标志位是否被设置为True

[python] view plain copy

import threading

import time

class Mon(threading.Thread):

def run(self):

Dinner.clear()

print('Cooking dinner')

time.sleep(3)

Dinner.set() #标志设置为True

print(self.name,':dinner is OK!')

class Son(threading.Thread):

def run(self):

while True:

if Dinner.isSet(): #判断标志位是否被设置为True

break

else:

print('dinner isnot ready!')

Dinner.wait(1)

print(self.name,':Eating Dinner')

def main():

mon = Mon()

son = Son()

mon.name = 'Mon'

son.name = 'Son'

mon.start()

son.start()

if __name__ == '__main__':

Dinner = threading.Event()

main()

'''''

Cooking dinner

dinner isnot ready!

dinner isnot ready!

dinner isnot ready!

Mon :dinner is OK!

Son :Eating Dinner

'''

8.线程的同步---Condition条件变量

条件变量表示当线程满足某一个 条件才被唤醒,否则一直阻塞

对比 只用锁不用条件变量 的好处就是:只用锁的话,如果一个线程在上锁后,解锁前,因为某一条件一直阻塞着,那么锁就一直解不开,那么其他线程也就因为一直获取不了锁而跟着阻塞着,这样效率就不好,浪费了很多时间。对于这种情况,锁+条件变量可以让该线程先 解锁,然后阻塞着,等待条件满足了,再重新唤醒并获取锁(上锁)。这样就不会因为一个线程阻塞着而影响其他线程也跟着阻塞了。

Condition 提供的方法:

acquire() 和 release() 表示上锁和解锁,和 单纯的锁机制一样。

wait() 解开锁,阻塞,直到其他线程调用了notify()或者notifyAll才被唤醒,注意,这里的wait()跟上面Event提到的wait()不是同一样东西

notify() 发出资源可用的信号,唤醒任意一条因 wait()阻塞的进程

notifyAll() 发出资源可用信号,唤醒所有因wait()阻塞的进程

下面给出一个例子,一家蛋糕店:只会做一个蛋糕,卖出后才会再做一个。绝对不会做积累到2个蛋糕。

[python] view plain copy

import threading

import time

class Server(threading.Thread):

def run(self):

global x

while True:

con.acquire()

while x>0:

con.wait()

x += 1

time.sleep(1)

print(self.name,':I make %d cake!'%(x))

con.notifyAll()

con.release()

class Client(threading.Thread):

def run(self):

global x

con.acquire()

while x == 0:

con.wait()

x-=1

print(self.name,'I bought a cake! the rest is %d cake'%(x))

con.notifyAll()

con.release()

def main():

ser = Server()

ser.name = 'Cake Server'

client = []

for i in range(3):

client.append(Client())

ser.start()

for c in client:

c.start()

if __name__ =='__main__':

x = 0

con = threading.Condition()

main()

'''''

打印结果:

Cake Server :I make 1 cake!

Thread-3 I bought a cake! the rest is 0 cake

Cake Server :I make 1 cake!

Thread-4 I bought a cake! the rest is 0 cake

Cake Server :I make 1 cake!

Thread-2 I bought a cake! the rest is 0 cake

Cake Server :I make 1 cake!

'''

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值