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
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/chen-huan/p/10663881.html

时间: 2024-07-30 22:44:03

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

C#中Thread类中Join方法的理解(转载)

指在一线程里面调用另一线程join方法时,表示将本线程阻塞直至另一线程终止时再执行      比如 Java代码   using System; namespace TestThreadJoin { class Program { static void Main() { System.Threading.Thread x = new System.Threading.Thread(new System.Threading.ThreadStart(f1)); x.Start(); Console

Android中回调函数的理解---本人Android纯新手

本人大二,刚刚接触Android,也刚刚申请的cnblog博客,说一下对Android中回调函数的理解,Android中回调函数和C++.JAVA中的默认构造函数差不多,即运行到了一定的代码时自动调用的代码,而Android中的回调函数和C++.JAVA中的默认构造函数的区别在于:C++.JAVA中的默认构造函数在创建一个对象时自动调用,而Android中的回调函数的自动调用是在比如按了HOME键之后.

python 中join()函数strip() 函数和 split() 函数的详解及实例

1.join()函数 Python中有join()和os.path.join()两个函数,具体作用如下: join():                连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 语法:  'sep'.join(seq) 参数说明sep:分隔符.可以为空seq:要连接的元素序列.字符串.元组.字典上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新的字符串 返回值:返回一个以分隔符sep连接各个元素后生成的字符串 os.p

关于在C#中对函数重载理解

函数重载是个什么概念,才接触的这个概念的时候我也是完全昏了,还在自己看看了书后就理解了.那什么是函数重载呢?我个人理解的是在同一个作用域下有多个同名的函数,但是他们的形参的类型是不同的,或者参数个数是不同的.当我们调用这些函数时,怎么判断我们调用的是那一个函数呢,这个就要看你在使用重载函数时所传参数的类型或者参数个数.好了,话不说.看看代码就知道了. using System;namespace overload{    class a    {        public void print

python中join()函数的使用方法

函数:string.join() Python中有join()和os.path.join()两个函数,具体作用如下:    join():    连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符)连接生成一个新的字符串    os.path.join():  将多个路径组合后返回 一.函数说明 1.join()函数 语法:  'sep'.join(seq) 参数说明sep:分隔符.可以为空seq:要连接的元素序列.字符串.元组.字典上面的语法即:以sep作为分隔符,将seq所有的

python中sorted函数的理解(对list列表排序,对dict字典排序)

在python手册中: sorted(iterable[,cmp,[,key[,reverse=True]]]) 作用:Return a new sorted list from the items in iterable. 第一个参数是一个iterable,返回值是一个对iterable中元素进行排序后的列表(list). 可选的参数有三个,cmp.key和reverse. 1)cmp指定一个定制的比较函数,这个函数接收两个参数(iterable的元素),如果第一个参数小于第二个参数,返回一个

python中strip()函数的理解

1.strip()函数 函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm) :删除s字符串中开头.结尾处,位于 rm删除序列的字符 s.lstrip(rm) :删除s字符串中开头处,位于 rm删除序列的字符 s.rstrip(rm) :删除s字符串中结尾处,位于 rm删除序列的字符 现在来分析s.strip(rm)这个函数. 现在假设s='abcd' 则 s.strip('bd')----->'abc' 而s.strip('ba')和s.strip('ab')的结果是一样

QEMU代码中os_daemonize()函数的理解

之前是做几年的Windows c++开发,Linux下的经验不够丰富,导致我在看QEMU代码时,有些地方还需要回头学习Linux操作系统的实现机制才能更准确理解.学习Linux操作系统时泛泛地看了很多书籍,好像明白了,但是要深刻理解,以这平庸的智商我觉得还是要多看代码多码代码.闲话少说,来看下os-posix.c中的一个函数,叫os_daemonize(),从名字上我们就知道是要搞一个守护进程,代码如下: void os_daemonize(void) { if (daemonize) { pi

python中thread模块中join函数

http://www.cnblogs.com/vingi/articles/2657790.html for i in range(10): t = ThreadTest(i) thread_arr.append(t) for i in range(10): thread_arr[i].start() for i in range(10): thread_arr[i].join() 简单说,阻塞进程指导线程执行完毕.通用的做法是我们启动一批线程,最后join这些线程结束. 总结:1 join方法