概述
多任务编程(一)
一、threading模块
1、如何使用threading模块创建子线程
(1)创建子线程之1:
import threading
import time
def hello():
print("hello world!")
time.sleep(5)
# 主线程
def main():
for i in range(0, 1):
t1 = threading.Thread(target=hello) # 定义一个子线程,这里的target用于传入函数名称
t1.start() # 创建并启动一个子线程,让线程开始执行
if __name__ == "__main__":
main()
当调用thread的时候并不会创建子线程,当调用thread创建的对象的start方法时,创建并执行线程
(2)创建子线程之2:
import threading
import time
# 通过定义一个类,该类必须继承Thread类,来实现子线程的创建
class Mythread(threading.Thread):
# Thread的方法start会自动调用run方法,因此必须定义run方法
def run(self):
for i in range(5):
time.sleep(5)
msg = self.name + "@" + str(i)
print(msg)
print(threading.enumerate())
if __name__ == "__main__":
t = Mythread()
print(threading.enumerate())
t.start()
print(threading.enumerate())
2、查看线程数量
使用threading.enumerate()方法查看当前程序中的所有线程
import threading
import time
def test1():
for i in range(10):
print("test1-----")
time.sleep(2)
# 创建子线程的函数运行结束,则子线程也就结束
def test2():
for i in range(10):
print("test2---------")
time.sleep(2)
def main():
print("----开始时间-----:%s" % time.ctime())
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
time.sleep(2)
while True:
length = len(threading.enumerate()) # 获取当前程序里的所有线程,返回一个列表
print("当前运行的线程个数:%s" % length)
print("线程名称:")
for temp in threading.enumerate():
print(temp)
time.sleep(10)
if length <= 1:
break
if __name__ == "__main__":
main()
3、多线程共享全局变量
在一个函数中,对全局变量进行修改时,是否需要使用global进行说明?
主要在于:这个操作有没有对全局变量的执行指向进行修改
(1)如果修改了执行指向,则必须使用global说明
(2)如果没有修改执行指向,仅仅是修改了指向的内容,则不必使用global声明
import threading
import time
def test1(temp):
temp.append(33)
print("-----in test1 nums=%s----" % str(temp))
def test2(abc):
print("-----in test3 nums%s----" % str(abc))
def test3(temp):
global nums
nums += temp
print("-----in test3 nums=%s----" % str(nums))
nums = [22, 55]
if __name__ == "__main__":
t1 = threading.Thread(target=test1, args=(nums,))
t2 = threading.Thread(target=test2, args=(nums,))
t3 = threading.Thread(target=test3, args=(nums,))
t1.start()
time.sleep(2)
t2.start()
time.sleep(2)
t3.start()
time.sleep(2)
print("-----main ----nums=%s----" % str(nums))
如果对于该不该使用global时机不清的话,建议使用pycharm来写代码,它会主动提示这个问题。
4、线程同步
(1)资源竞争
import threading
import time
num = 0
def test1(temp):
global num
for i in range(temp):
num += 1
print("-----in test1 num=%s----" % str(num))
def test2(temp):
global num
for i in range(temp):
num += 1
print("-----in test2 num=%s----" % str(num))
def test3(temp):
global num
for i in range(temp):
num += 1
print("-----in test2 num=%s----" % str(num))
if __name__ == "__main__":
nums = 1000000
t1 = threading.Thread(target=test1, args=(nums,))
t2 = threading.Thread(target=test2, args=(nums,))
t3 = threading.Thread(target=test3, args=(nums,))
t1.start()
t2.start()
t3.start()
print("-----main ----num=%s----" % str(num))
执行结果:
-----main ----num=1074075----
-----in test1 num=1177315----
-----in test2 num=1426154----
-----in test2 num=1602839----
学过操作系统的应该很清楚为什么会这样,这里不再赘述
(2)互斥锁
- 一种加锁方式,把锁加在循环外面:
import threading
import time
num = 0
def test1(temp):
global num
# 上锁,如果没有上锁则直接上锁
# 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
mutex.acquire()
for i in range(temp):
num += 1
# 解锁
mutex.release()
print("-----in test1 num=%s----" % str(num))
def test2(temp):
global num
# 上锁,如果没有上锁则直接上锁
# 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
mutex.acquire()
for i in range(temp):
num += 1
# 解锁
mutex.release()
print("-----in test2 num=%s----" % str(num))
def test3(temp):
global num
# 上锁,如果没有上锁则直接上锁
# 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
mutex.acquire()
for i in range(temp):
num += 1
# 解锁
mutex.release()
print("-----in test3 num=%s----" % str(num))
mutex = threading.Lock()
if __name__ == "__main__":
nums = 1000000
t1 = threading.Thread(target=test1, args=(nums,))
t2 = threading.Thread(target=test2, args=(nums,))
t3 = threading.Thread(target=test3, args=(nums,))
t1.start()
t2.start()
t3.start()
print("-----main ----num=%s----" % str(num))
执行结果:
-----main ----num=148062----
-----in test1 num=1000000----
-----in test2 num=2000000----
-----in test3 num=3000000----
反复执行该程序,可以看到,虽然main那里的num会发生变化,但是其余的不会(这和操作系统的调度算法有关系,一般来说:test1、test2、test3这三个子线程的优先级是一样,应该是按照创建时间的先后进入队列,所以执行顺序是:test1、test2、test3)这是因为,主线程运行到print时,num还没有加完就直接被读取输出了
- 另一种加锁方式,把锁加在循环内部:
import threading
import time
num = 0
def test1(temp):
global num
for i in range(temp):
# 上锁,如果没有上锁则直接上锁
# 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
mutex.acquire()
num += 1
# 解锁
mutex.release()
print("-----in test1 num=%s----" % str(num))
def test2(temp):
global num
for i in range(temp):
# 上锁,如果没有上锁则直接上锁
# 如果已经有线程先一步上锁了,则阻塞,直到解锁为止
mutex.acquire()
num += 1
# 解锁
mutex.release()
print("-----in test2 num=%s----" % str(num))
def test3(temp):
global num
for i in range(temp):
# 上锁,如果没有上锁则直接上锁
# 如果已经有线程先一步上锁了,则阻塞,直到解锁为止
mutex.acquire()
num += 1
# 解锁
mutex.release()
print("-----in test3 num=%s----" % str(num))
mutex = threading.Lock()
if __name__ == "__main__":
nums = 1000000
t1 = threading.Thread(target=test1, args=(nums,))
t2 = threading.Thread(target=test2, args=(nums,))
t3 = threading.Thread(target=test3, args=(nums,))
t1.start()
t2.start()
t3.start()
print("-----main ----num=%s----" % str(num))
执行结果:
-----main ----num=30463----
-----in test1 num=2934771----
-----in test3 num=2994796----
-----in test2 num=3000000----
可以看到和方法一的不一样,这里稍微解释一下:
假设第一个上锁的时test1线程,它在上锁之后,执行+1操作,此时test2、test3都处在阻塞状态,但是随后test1解锁,于是按照算法,test2或者test3会对其进行上锁,这么一来test1也会处于阻塞状态,最后输出的时候,就不再是1000000了
(3)银行家算法
最后
以上就是健壮香氛为你收集整理的多任务编程(一)多任务编程(一)的全部内容,希望文章能够帮你解决多任务编程(一)多任务编程(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复