文章目录
1. 进程与线程的概念
1.1 进程
进程:进程是操作系统进行资源分配和调度运行的基本单位,一个正在运行的程序就是一个进程。
查看进程的两种方法:
- 打开Windows任务管理器
- 打开cmd,输入命令
tasklist
1.打开Windows任务管理器如下:Google Chrome这个应用,后面有数字(24)
,代表这个应用正在运行24个进程。
2.打开cmd,输入命令tasklist
如下:
1.2 线程
线程:线程是程序执行的最小单元,进程负责分配资源,而线程是使用分配的资源去执行程序。
- 进程是线程的容器,一个进程下最少有一个线程。
- 一个进程下的所有线程,共享该进程的所有资源。
2. threading模块
1.threading模块的方法:
方法 | 描述 |
---|---|
threading.currentThread() | 返回当前的线程变量 |
threading.enumerate() | 返回一个包含正在运行的线程列表 |
threading.activeCount() | 返回正在运行的线程数量 |
2.threading模块的Thread类的方法:
方法 | 描述 |
---|---|
run() | 用以表示线程活动的方法 |
start() | 启动线程活动 |
join() | 等待至线程中止 |
isAlive() | 返回线程是否活动的 |
getName() | 返回线程名 |
setName() | 设置线程名 |
3.threading模块的Lock类的方法:
方法 | 描述 |
---|---|
acquire() | 获得锁 |
release() | 释放锁 |
2.1 threading模块的方法
2.2 多线程的创建与使用
1.通过threading.Thread()
创建对象,并使用多线程。
import threading
def test1():
for i in range(1,6):
print(i)
def test2(x,y):
for i in range(x,y):
print(i)
if __name__=="__main__":
t1 = threading.Thread(name='thread1', target=test1) # name的值为线程名,target的值为函数名
t2 = threading.Thread(name='thread2', target=test2, args=(11,16)) # args的值为函数的传参
t1.start() # 启动线程thread1
t2.start() # 启动线程thread2
运行结果:
1
2
11
12
3
4
13
14
15
5
1.从运行结果可以看出,多线程是并发的
2.多运行几次程序,会发现每次运行结果不一致
2.通过继承threading.Thread
类,然后重写__init__()
方法和run()
方法,再创建对象,并使用多线程。
import threading
class myThread(threading.Thread):
def __init__(self, name, target):
threading.Thread.__init__(self)
self.name = name
self.target = target
def run(self):
print("启动线程: {}".format(self.name))
self.target()
def test1():
for i in range(1,6):
print(i)
def test2():
for i in range(11,16):
print(i)
if __name__=="__main__":
t1 = myThread(name='thread1', target= test1)
t2 = myThread(name='thread2', target= test2)
t1.start()
t2.start()
运行结果:
启动线程: thread1
1
启动线程: thread2
11
12
13
14
2
15
3
4
5
2.3 主线程与守护线程
主线程:主线程会等待所有的子线程运行结束后,再结束。
守护线程:当设置一个线程为守护线程后,随着主线程的结束,守护线程也会跟着结束。
例1:一个主线程,两个子线程。
- 设置子线程1为守护线程;
- 主线程先后调用子线程1和子线程2;
- 构造子线程1的运行时间大于子线程2;
- 主线程等待两个子线程运行,子线程2先运行结束,子线程1本来也还在运行,但由于主线程和子线程2都结束了,作为守护线程的子线程1也跟着结束。
import threading
import time
def test1():
print("Hello World")
time.sleep(2)
print("Hello World")
def test2():
for i in range(1,6):
print(i)
if __name__=="__main__":
t1 = threading.Thread(name='thread1', target=test1)
t2 = threading.Thread(name='thread2', target=test2)
t1.daemon = True # 设置守护线程
t1.start()
t2.start()
运行结果:
Hello World
1
2
3
4
5
1.注意:设置守护线程要在放在线程启动之前,即
t.daemon = True
要放在t.start()
之前。
2.看结果可以发现,本来子线程thread1
要打印两次Hello World
,但是因为主线程和子线程thread2
都运行结束了,thread1
作为守护线程,也跟着结束了,所以第二次Hello World
没有打印。
例2:一个主线程,两个子线程。
- 子线程1无限循环,设置子线程1为守护线程;
- 子线程2运行时间有限;
- 相当于子线程2运行结束,子线程1就跳出了无限循环。
import threading
import time
from datetime import datetime
def test1():
while True:
print(datetime.now())
time.sleep(0.5)
def test2():
for i in range(1,6):
print(i)
time.sleep(0.5)
if __name__=="__main__":
t1 = threading.Thread(name='thread1', target=test1)
t2 = threading.Thread(name='thread2', target=test2)
t1.daemon = True # 设置守护线程
t1.start()
t2.start()
运行结果:
2022-11-04 22:38:41.222094
1
2022-11-04 22:38:41.733547
2
3
2022-11-04 22:38:42.241197
2022-11-04 22:38:42.751068
4
2022-11-04 22:38:43.253057
5
2.4 线程阻塞
使用join()可以实现线程阻塞,从而控制线程运行的先后顺序。
注:
- join()不设置时间,则等待线程结束后,再执行后续代码。
- join(3)设置时间3秒,则等待线程执行3秒后,再执行后续代码。
1.等待执行线程1结束后,再执行主线程和线程2。
import threading
def test1():
for i in range(1,6):
print(i)
def test2(x,y):
for i in range(x,y):
print(i)
if __name__=="__main__":
t1 = threading.Thread(name='thread1', target=test1)
t2 = threading.Thread(name='thread2', target=test2, args=(11,16))
t1.start()
t1.join() # 等待线程thread1结束后,再执行后续代码
t2.start()
print("hello world")
运行结果:
1
2
3
4
5
11
hello world
12
13
14
15
2.等待执行线程1结束后,再等待执行线程2结束,最后执行主线程。
import threading
def test1():
for i in range(1,6):
print(i)
def test2(x,y):
for i in range(x,y):
print(i)
if __name__=="__main__":
t1 = threading.Thread(name='thread1', target=test1)
t2 = threading.Thread(name='thread2', target=test2, args=(11,16))
t1.start()
t1.join() # 等待线程thread1结束后,再执行后续代码
t2.start()
t2.join() # 等待线程thread2结束后,再执行后续代码
print("hello world")
运行结果:
1
2
3
4
5
11
12
13
14
15
hello world
3.等待执行线程1运行3秒后,再执行主线程和线程2。
import threading
import time
def test1():
for i in range(1,6):
print(i)
time.sleep(1)
def test2(x,y):
for i in range(x,y):
print(i)
if __name__=="__main__":
t1 = threading.Thread(name='thread1', target=test1)
t2 = threading.Thread(name='thread2', target=test2, args=(11,16))
t1.start()
t1.join(3) # 等待线程thread1运行3秒后,再执行后续代码
t2.start()
print("hello world")
运行结果:
1
2
3
11
hello world
12
13
14
15
4
5
2.5 线程同步
多个线程同时运行,由于多线程是并发的,各个线程之间会互相抢占计算资源,导致程序混乱。
如果多个线程共同对某个数据修改,可能会出现数据不同步的问题,为了保证数据的正确性,需要进行多线程同步。
使用threading.Lock()
,可以对线程进行上锁和解锁,从而实现程同步,其中:
acquire()
方法用于给线程上锁release()
方法用于给线程解锁
1.未对线程上锁,并对变量number
进行修改,运行后发现很混乱,不符合预期结果。
import threading
number = 0
def update_number():
global number
print("old number:{}".format(number))
number += 10
print("new number:{}".format(number))
print("---------------")
if __name__=="__main__":
# 创建5个线程,添加进列表
threadList = []
for i in range(5):
t = threading.Thread(target=update_number)
threadList.append(t)
# 依次启动5个线程
for t in threadList:
t.start()
运行结果:
old number:0
new number:10
old number:10
new number:20
---------------
---------------
old number:10
new number:30
---------------
old number:20
new number:40
---------------
old number:40
new number:50
---------------
2.对线程上锁,并对变量number
进行修改,运行后符合预期结果。
import threading
number = 0
threadLock = threading.Lock() # 创建Lock对象
def update_number():
threadLock.acquire() # 获得锁
global number
print("old number:{}".format(number))
number += 10
print("new number:{}".format(number))
print("---------------")
threadLock.release() # 释放锁
if __name__=="__main__":
# 创建5个线程,添加进列表
threadList = []
for i in range(5):
t = threading.Thread(target=update_number)
threadList.append(t)
# 依次启动5个线程
for t in threadList:
t.start()
运行结果:
old number:0
new number:10
---------------
old number:10
new number:20
---------------
old number:20
new number:30
---------------
old number:30
new number:40
---------------
old number:40
new number:50
---------------
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84875.html