我是靠谱客的博主 健壮香氛,这篇文章主要介绍多任务编程(一)多任务编程(一),现在分享给大家,希望可以做个参考。

多任务编程(一)

一、threading模块

1、如何使用threading模块创建子线程

(1)创建子线程之1:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()方法查看当前程序中的所有线程

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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声明

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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)资源竞争

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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))

执行结果:

复制代码
1
2
3
4
5
-----main ----num=1074075---- -----in test1 num=1177315---- -----in test2 num=1426154---- -----in test2 num=1602839----

学过操作系统的应该很清楚为什么会这样,这里不再赘述

(2)互斥锁

  • 一种加锁方式,把锁加在循环外面:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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))

执行结果:

复制代码
1
2
3
4
5
-----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还没有加完就直接被读取输出了

  • 另一种加锁方式,把锁加在循环内部:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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))

执行结果:

复制代码
1
2
3
4
5
-----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)银行家算法

最后

以上就是健壮香氛最近收集整理的关于多任务编程(一)多任务编程(一)的全部内容,更多相关多任务编程(一)多任务编程(一)内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部