Python多线程的理解和使用(一)Threading中join()函数的理解

1. 多线程的概念

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

使用线程可以把占据长时间的程序中的任务放到后台去处理。
用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度 
程序的运行速度可能加快
在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

线程可以被抢占(中断)。
在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让。
 

2. Threading 多进程的使用案例:join()函数的理解

     通过以下实例可以get到join()函数的作用:如果thread是某个子线程,则调用thread.join()的作用是确保thread子线程执行完毕后才能执行下一个线程。下面第一个例子中没有调用join()函数,故没有这个限制,所有线程执行顺序都不定。

     第二个例子中在每个子线程启动start()后马上调用了join()函数,这就确保了对于每一个子线程,必须等它执行完毕后才能执行下一个程序,故子线程是按顺序执行的,且主线程中的print()方法是在所有的子线程执行完毕后才执行。

    第三个例子中,对于子线程启动start()后没有马上调用join()函数,故子线程的执行顺序是不确定的,但是主线程中的print()前调用了每个子线程的join()函数,故print()要在所有的子线程执行完毕后才能执行。

(1)没有使用join()函数,线程执行顺序不定,主线程可能在所有子线程执行完之前就执行了

import threading
import time

def test(p):
time.sleep(0.001)
print(p)

ts = []

for i in range(15):
# target指定线程要执行的代码,args指定该代码的参数
th = threading.Thread(target=test, args=[i])
ts.append(th)

for i in ts:
i.start()

print("it is end !")



0
1
it is end !
4
2
3
5
(2)修改部分代码如下:每次启动子线程后,调用一次join()函数,可以看出线程按顺序执行,且主线程在所有子线程执行完之              后才执行。

for i in ts:
i.start()
# 此处的join函数子线程按顺序执行,即i线程跑完后才能继续跑下一个线程
i.join()


print("it is end !")



0
1
2
3
4
5
it is end !
(3)修改部分代码如下:可以看出子线程执行顺序不定,但是主线程是在所有子线程执行完毕之后才执行的。

for i in ts:
i.start()

# 此处的join函数使子线程全部跑完再继续往下跑子线程
for i in ts:
i.join()

print("it is end !")


1
0
4
5
2
3
it is end !
 

3. 全局锁

(1)全局锁(GIL)是一个很重要的概念。

在任意一个指定的时间,有且只有一个线程在运行 -》 python是线程安全的

(2)io操作经常用到多线程,如在修改某个文档时,其他线程是不能进来干扰的。

    a. 加锁:acquire , 释放锁:release,   有加锁就一定要释放锁

(3).rlock 可重入锁: 如果前面忘记了release释放锁,正常是无法再获取锁的,rlock可实现再获取锁。

(4)实例:mlock.acquire()和mlock.release()之间的代码是不间断执行的,不会被其他线程干扰。

import threading

mlock = threading.Lock()
lst = list(range(20))

def change():
global lst
# mlock.acquire() # 加锁
lst = [i+1 for i in lst]
lst = [i*2 for i in lst]
# mlock.release() #释放锁

print(lst)

for i in range(6):
d = threading.Thread(target=change)
d.start()


[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40]
[6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66, 70, 74, 78, 82]
[14, 22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 142, 150, 158, 166]
[30, 46, 62, 78, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 254, 270, 286, 302, 318, 334]
[62, 94, 126, 158, 190, 222, 254, 286, 318, 350, 382, 414, 446, 478, 510, 542, 574, 606, 638, 670]
[126, 190, 254, 318, 382, 446, 510, 574, 638, 702, 766, 830, 894, 958, 1022, 1086, 1150, 1214, 1278,  1342]
---------------------
作者:zhuzuwei
来源:CSDN
原文:https://blog.csdn.net/zhuzuwei/article/details/80927554
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/chen-huan/p/10663881.html