1. 线程的介绍
线程是进程中执行代码的一个分支,每个执行分支(线程)要想工作执行代码需要cpu进行调度 ,也就是说线程是cpu调度的基本单位,每个进程至少都有一个线程,而这个线程就是我们通常说的主线程。
实现:
首先要进行模块的导入
import threading
"""
实现多任务的另一种方式
进程:资源分配
线程:cpu调度的最小单位
线程实现多任务
"""
import threading
import time
def task1():
th1 = threading.current_thread()
print('th', th1)
for i in range(5):
print('task1--', i)
time.sleep(0.5)
def task2():
th2 = threading.current_thread()
print('th', th2)
for i in range(5):
print('task2--', i)
time.sleep(0.5)
if __name__ == '__main__':
# 获取线程的的对象
th = threading.current_thread()
print('th', th)
# 创建线程
t1 = threading.Thread(target=task1, name='t1')
t2 = threading.Thread(target=task2, name='t2')
# 未执行之前
print(t1)
print(t2)
# 启动线程
t1.start()
t2.start()
# 执行以后
print(t1)
print(t2)
1.2 多线程的实现方式
Thread类的参数说明
Thread([group [, target [, name [, args [, kwargs]]]]])
group: 线程组,目前只能使用None
target: 执行的目标任务名
args: 以元组的方式给执行任务传参
kwargs: 以字典方式给执行任务传参
name: 线程名,一般不用设置
agrs与kwagrs传参
"""
线程之间的执行顺序是无序的
"""
import threading
import time
def task1(count):
for i in range(count):
print('task1--', i)
time.sleep(0.5)
def task2(con, count):
for i in range(count):
print(con, i)
time.sleep(0.5)
if __name__ == '__main__':
# 获取线程的的对象
th = threading.current_thread()
print('th', th)
# 创建线程
# 传参的方式args 元组
# t1 = threading.Thread(target=task1,name='t1',args=(5,))
# t2 = threading.Thread(target=task2,name='t2',args=('hello',5))
# kwargs的方式 字典的形式
t1 = threading.Thread(target=task1, name='t1', kwargs={'count': 5})
t2 = threading.Thread(target=task2, name='t2', kwargs={'count': 5, 'con': 'hello'})
t1.start()
t2.start()
1.3 线程的注意事项
线程之间执行是无序的
主线程会等待所有的子线程执行结束再结束
线程之间共享全局变量
线程之间共享全局变量数据出现错误问题
设置守护主线程
"""
主线程执行完,子线程自动销毁
"""
import threading
import time
def task():
for i in range(5):
print(i)
time.sleep(0.5)
if __name__ == '__main__':
# 方式一
# t1 = threading.Thread(target=task,daemon=True)
t1 = threading.Thread(target=task)
# 方式二 都要设置在start之前
t1.setDaemon(True)
t1.start()
time.sleep(1)
print('over')
1.4 线程之间共享全局变量
"""
线程在进程里边,调用线程的资源,所以线程是共享资源的
而进程是相互独立的,不进行数据的共享
进程间的资源是独立的
"""
import threading
import time
m_list = []
def add_data():
for i in range(5):
print(i)
m_list.append(i)
time.sleep(0.5)
print('add:', m_list)
def read_data():
print('read:', m_list)
if __name__ == '__main__':
t1 = threading.Thread(target=add_data)
t2 = threading.Thread(target=read_data)
t1.start()
t1.join()
t2.start()
print('main', m_list)
共享数据之间的资源竞争问题
"""
"""
import threading
import time
m_sum = 0
def task1():
for _ in range(1000000):
global m_sum
m_sum += 1
t = threading.current_thread()
print(f'{t.name} 结果: {m_sum}')
if __name__ == '__main__':
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task1)
t1.start()
t2.start()
time.sleep(5)
print('main', m_sum)
解决办法:互斥锁的应用
方式一:线程同步
import threading
import time
m_sum = 0
def task1():
global m_sum
for _ in range(1000000):
m_sum += 1
t = threading.current_thread()
print(f'{t.name} 的执行结果{m_sum}')
if __name__ == '__main__':
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task1)
t1.start()
# 方式1 join 线程同步,t1执行完在执行t2
# 弊端:效率不高
t1.join()
t2.start()
time.sleep(2)
print('main', m_sum)
方式二:互斥锁
"""
加锁解决问题
"""
import threading
import time
m_sum = 0
# 创建一个锁
th_lock = threading.Lock()
def task1():
global m_sum
# 加锁
th_lock.acquire()
for _ in range(1000000):
m_sum += 1
# 解锁
th_lock.release()
t = threading.current_thread()
print(f'{t.name} 的执行结果: {m_sum}')
if __name__ == '__main__':
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task1)
t1.start()
t2.start()
time.sleep(2)
print('main', m_sum)
加锁异步
"""
加锁解决问题
锁的位置不同
"""
import threading
import time
m_sum = 0
# 创建一个锁
th_lock = threading.Lock()
def task1():
global m_sum
for _ in range(1000000):
# 加锁 加到里边会产生效率的问题
th_lock.acquire()
m_sum += 1
# 解锁
th_lock.release()
t = threading.current_thread()
print(f'{t.name} 的执行结果: {m_sum}')
if __name__ == '__main__':
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task1)
t1.start()
t2.start()
time.sleep(2)
print('main', m_sum)
1.5 死锁的产生
一直在等待对方的先进行的方式
"""
"""
import threading
my_list = [1, 2, 3]
# 创建一个锁
t_look = threading.Lock()
def task(index):
t1 = threading.current_thread()
# 加锁
t_look.acquire()
if index >= len(my_list):
print('超出下标的范围')
# 解锁
t_look.release()
return
print(f'{t1.name}的取第{index}个的值为{my_list[index]}')
# 解锁 只加一个会出现死锁的问题
t_look.release()
if __name__ == '__main__':
for i in range(5):
t = threading.Thread(target=task, args=(i,))
t.start()
2.进程与线程的对比
关系:
线程是依附在进程里面的,没有进程就没有线程。
一个进程默认提供一条线程,进程可以创建多个线程。
区别:
进程之间不共享全局变量
线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁或者线程同步
创建进程的资源开销要比创建线程的资源开销要大
进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
线程不能够独立执行,必须依存在进程中
多进程开发比单进程多线程开发稳定性要强
进程优缺点:
优点:可以用多核
缺点:资源开销大
线程优缺点:
优点:资源开销小
缺点:不能使用多核