Python多线程
多任务不仅可以使用多进程完成,也可使用多线程完成。
一个进程可以包含很多线程,但至少含有一个线程。
Python提供了 _thread和threading两个模块,供我们使用多线程。_thread是低级模块,threading是高级模块。我们通常使用threading来实现多线程的相关功能。
使用线程读取文件内容。
- 读取文件内容的方法
- 创建线程,并将方法绑定到线程上
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
'多线程'
__author__ = 'click'
__date__ = '2018/7/23 下午6:20'
import time, threading
def threadReadFile():
print('主线程的名字%s' % threading.current_thread().name)
# print('读取文件中内容是%s' % myio.ReadAndWrite.readTxt())
n = 0
while n < 10:
n = n + 1
print('执行相加操作结果是%s' % n)
t = threading.Thread(target=threadReadFile, name='threadReadFile')
t.start()
t.join()
print("当前线城是%s" % threading.current_thread().name)
运行结果:
主线程的名字threadReadFile
执行相加操作结果是10
当前线城是MainThread
使用线程之前,先<font color = red >import threading</font>要使用的threading模块。
t = threading.Thread(target=threadReadFile, name='threadReadFile')
初始化一个线程。
target:指定线程要执行的任务。
name:创建的线程的名称。
这样就实现了新创建一个线程,执行新任务。
提到多线程,就要考虑多线程之间操作同一变量时候,出现<font color = red >脏数据</font>的问题。
来看看多线程是怎么样操作变量数据,导致多线程获取数据时候出错的。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
'多线程锁的问题'
__author__ = 'click'
__date__ = '2018/7/24 下午3:46'
import time, threading
'出现多线程数据混乱的问题:线程之间共享创建的全局变量' \
'多进程之间的变量:进程间相互独立的,不存在多进程操作同一变量' \
'多线程:共享同一变量,存在多线程对同一变量操作的情况'
#####################################
'多线程造成变量数据改变的原因' \
'原因是因为高级语言的一条语句在CPU执行时是若干条语句,即使一个简单的计算:'
'balance = balance + n'
'也分两步:'
'计算balance + n,存入临时变量中;'
'将临时变量的值赋给balance。'
'也就是可以看成:'
'x = balance + n'
'balance = x' \
####################################
'使用线程锁,对操作变量的方法进行加锁,保证变量值发生改变时只有一个线程对其操作。单线程的模式'
balance = 0
# 初始化一个锁
# 1. lock = threading.Lock()
def change_it(n):
global balance
balance = balance + n
balance = balance - n
def run_thread(n):
for i in range(1000000):
# 1.首先申请锁
# lock.acquire()
try:
change_it(n)
finally:
# 使用try finaly 保证执行完之后,释放锁
# lock.release()
t1 = threading.Thread(target=run_thread, args=(4,))
t2 = threading.Thread(target=run_thread, args=(6,))
t1.start()
t2.start()
t1.join()
t2.join()
print('balance %s' % balance)
先把锁相关的代码注释掉。
运行结果:
balance 4
按照代码正常的逻辑应该是如下:
n=4情况:
banlance =0
banlance = banlance+4 ->= banlance = 0+4 = 4
banlance = banlance-4 ->= banlance = 4-4 = 0
n=6情况:
banlance = 0
banlance = banlance +6 ->= banlance = 0+6 = 6
banlance = banlance -6 ->= banlance = 6-6 = 0
最后执行的结果banlance应该是0
那为什么会是4 呢?
创建多线程时候,应该按照先相加后相减。但是由于线程的调度是由操作系统直接控制。当t1,t2执行时,会出现<font color = red>交替执行</font>的情况。这样最后banlance的值就不等于0。
这里面具体的原因是高级语言在执行一下代码时候,分为两部分执行,
banlance = banlance+n
1.计算banlance+n,并将值赋值给临时变量
2.将临时变量赋值给banlance
这样我们就清楚了,因为操作系统在执行代码时候分两步,当多线程执行时候,就会出现
t1
banlance = 0
banlance = banlnace +4 ->= x = 0+4 = 4
t2
banlance = 0
banlance = banlance +6 ->= Y = 0+6 = 6
最终
banlance = Y
当t1代码开始运行到banlance = X时候,banlance = 4。对于t2任务 banlance的数据已经是错的了。
综上,多线程导致数据出现错误的原因是,多个线程同时操作同一个变量,导致变量的值出现错误。
所以,我们要保证在t1在操作banlance的时候,其他的线程就不能操作banlance,其他的线程就要等待。只有当t1执行完毕,并释放了对banlance的锁,其他的线程才能进行操作banlance变量。
如何对一个变量进行加锁,
- 初始化一个锁
lock=threading.Lock() - 获取锁
lock.acquire() - 将要执行的代码使用try...finaly处理,并在finaly中释放锁 lock.realease()
也就是放开上述代码中的1、2、3处代码。
运行代码结果为:
banlance = 0