python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁

      线程也是实现多任务的一种方式,一个进程中,也经常需要同时做多件事,就需要同时运行多个‘子任务’,这些子任务就是线程。一个进程可以拥有多个并行的线程,其中每一个线程,共享当前进程的资源。

      线程可以看出是轻量级的进程。多个线程共享内存,线程切换的开销小

      进程和线程在使用上各有优缺点: 线程执行开销小, 但不利于资源的管理和保护, 而进程正相反

      在Python 程序中,可以通过“_thread”和 threading(推荐使用)这两个模块来处理线程。在 Python3 中, thread 模块已经废弃。可以使用 threading 模块代替。所以,在 Python3中不能再使用 thread 模块,但是为了兼容 Python3 以前的程序,在 Python3 中将 thread 模块重命名为“_thread”
 

使用_thread 模块

创建线程

当使用 thread 模块来处理线程时,可以调用里面的函数 start_new_thread()来生成一个新的线程
 

import _thread
import time

def fun1():
	print('开始运行fun1')
	time.sleep(4)
	print('运行fun1结束')

def fun2():
	print('开始运行fun2')
	time.sleep(2)
	print('运行fun2结束')

if __name__=='__main__':
	print('主进程开始运行')
	#启动一个线程运行函数 fun1
	_thread.start_new_thread(fun1,())
	#启动一个线程运行函数 fun2
	_thread.start_new_thread(fun2,())
	time.sleep(6)
	print('主进程结束运行')

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第1张图片

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第2张图片

fun1和fun2谁先开始不一定

 

为线程传递参数
 

import _thread
import time

def fun1(thread_name,delay):
	print('线程{0}开始运行 fun1'.format(thread_name))
	time.sleep(delay)
	print('线程{0}运行 fun1 结束'.format(thread_name))

def fun2(thread_name,delay):
	print('线程{0}开始运行 fun2'.format(thread_name))
	time.sleep(delay)
	print('线程{0}运行 fun2 结束'.format(thread_name))

if __name__=='__main__':
	print('开始运行')
	#启动一个线程运行函数 fun1
	_thread.start_new_thread(fun1,('thread-1',4))
	#启动一个线程运行函数 fun2
	_thread.start_new_thread(fun2,('thread-2',2))
	time.sleep(6)

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第3张图片

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第4张图片

 

_thread 模块

      Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。 _thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的

      在 Python3 程序中,对多线程支持最好的是 threading 模块,使用这个模块,可以灵活地创建多线程程序,并且可以在多线程之间进行同步和通信。

      在 Python3 程序中,可以通过如下两种方式来创建线程:

  • 通过 threading.Thread 直接在线程中运行函数
  • 通过继承类 threading.Thread 来创建线程

 

通过 threading.Thread 直接在线程中运行函数

import threading
import time

def fun1(thread_name,delay):
	print('线程{0}开始运行fun1'.format(thread_name))
	time.sleep(delay)
	print('线程{0}运行fun1结束'.format(thread_name))

def fun2(thread_name,delay):
	print('线程{0}开始运行fun2'.format(thread_name))
	time.sleep(delay)
	print('线程{0}运行fun2结束'.format(thread_name))

if __name__=='__main__':
	print('开始运行')
	#创建线程
	t1=threading.Thread(target=fun1,args=('thread-1',2))
	t2=threading.Thread(target=fun2,args=('thread-2',4))
	t1.start()
	t2.start()

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第5张图片

 

继承 threading.Thread 类创建线程
 

import threading
import time

def fun1(delay):
	print('线程{0}开始运行 fun1'.format(threading.current_thread().getName()))
	time.sleep(delay)
	print('线程{0}运行 fun1 结束'.format(threading.current_thread().getName()))

def fun2(delay):
	print('线程{0}开始运行 fun2'.format(threading.current_thread().getName()))
	time.sleep(2)
	print('线程{0}运行 fun2 结束'.format(threading.current_thread().getName()))

#创建线程类继承 threading.Thread
class MyThread(threading.Thread):
	#重写父类的构造方法,其中 func 是线程函数, args 是传入线程的参数,name 是线程名
	def __init__(self,func,name,args):
		super().__init__(target=func,name=name,args=args)
	#重写父类的 run()方法
	def run(self):
		self._target(*self._args)

if __name__=='__main__':
	print('开始运行')
	#创建线程
	t1=MyThread(fun1,'thread-1',(2,))
	t2=MyThread(fun2,'thread-2',(4,))
	t1.start()
	t2.start()

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第6张图片

 

线程共享全局变量

       在一个进程内所有线程共享全局变量,多线程之间的数据共享比多进程要好。但是可能造成多个进程同时修改一个变量(即线程非安全),可能造成混乱
 

import time
from threading import *

#定义全局变量 num
num=10

def test1():
	global num
	for i in range(3):
		num+=1
	print('test1 输出 num:',num)

def test2():
	global num
	print('test2 输出 num:',num)

if __name__=='__main__':
	t1=Thread(target=test1)
	t2=Thread(target=test2)
	t1.start()
	t1.join()
	t2.start()
	t2.join()

线程共享全局变量存在问题

t1和t2谁先执行都是随机的
 

import time
from threading import *

#定义全局变量 num
num=0

def test1():
	global num
	for i in range(100000):
		num+=1
	print('执行test1函数num的值:',num)

def test2():
	global num
	for i in range(100000):
		num+=1
	print('执行test2函数num的值:',num)

if __name__=='__main__':
	t1=Thread(target=test1)
	t2=Thread(target=test2)
	t1.start()
	t2.start()
	t1.join()
	t2.join()

按理说结果应该是100000和200000

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第7张图片

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第8张图片

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第9张图片

 

互斥锁

        如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。 最简单的同步机制就是引入互斥锁

       锁有两种状态——锁定和未锁定。 某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”状态,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

      使用 Thread 对象的 Lock 可以实现简单的线程同步,有上锁 acquire 方法和 释放release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和release 方法之间
 

      就和操作系统学的加锁机制一样

 

import time
from threading import Thread,Lock

#定义全局变量 num
num=0
#创建一把互斥锁
mutex=Lock()

def test1():
	global num
	'''
	在两个线程中都调用上锁的方法,则这两个线程就会抢着上锁,
	如果有 1 方成功上锁,那么导致另外一方会堵塞(一直等待)直到这个锁被解开
	'''
	mutex.acquire()#上锁
	for i in range(100000):
		num+=1
	mutex.release()
	print('test1 输出 num:',num)

def test2():
	global num
	mutex.acquire() # 上锁
	for i in range(100000):
		num+=1
	mutex.release()
	print('test2 输出 num:',num)

if __name__=='__main__':
	t1=Thread(target=test1)
	t2=Thread(target=test2)
	t1.start()
	t2.start()
	t1.join()
	t2.join()

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第10张图片

 

互斥锁改进

只对相加操作加锁,而不是对整个for循环加锁了

import time
from threading import Thread,Lock

#定义全局变量 num
num=0
#创建一把互斥锁
mutex=Lock()

def test1():
	global num
	'''
	在两个线程中都调用上锁的方法,则这两个线程就会抢着上锁,
	如果有 1 方成功上锁,那么导致另外一方会堵塞(一直等待)直到这个锁被解开
	'''
	for i in range(100000):
		mutex.acquire() # 上锁
		num+=1
		mutex.release()
	print('test1 输出 num:',num)

def test2():
	global num
	for i in range(100000):
		mutex.acquire() # 上锁
		num+=1
		mutex.release()
	print('test2 输出 num:',num)

if __name__=='__main__':
	t1=Thread(target=test1)
	t2=Thread(target=test2)
	t1.start()
	t2.start()
	t1.join()
	t2.join()

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第11张图片
 

死锁

在线程共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁
 

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第12张图片

 

import time
from threading import Thread,Lock
import threading

mutexA=threading.Lock()
mutexB=threading.Lock()

class MyThread1(Thread):
	def run(self):
		if mutexA.acquire():
			print(self.name,'执行')
			time.sleep(1)
			if mutexB.acquire():
				print(self.name,'执行')
				mutexB.release()
			mutexA.release()

class MyThread2(Thread):
	def run(self):
		if mutexB.acquire():
			print(self.name,'执行')
			time.sleep(1)
			if mutexA.acquire():
				print(self.name,'执行')
				mutexA.release()
			mutexB.release()	

if __name__ == '__main__':
	t1=MyThread1()
	t2=MyThread2()
	t1.start()
	t2.start()

python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁_第13张图片

一直卡在那了

 

你可能感兴趣的:(python多线程(一)——_thread & threading & 线程共享变量 & 互斥锁 & 死锁)