简介:今天,首席CTO Note将与您分享多少秒钟来完成Python线程。如果您可以解决您现在面临的问题,请不要忘记注意此网站。让我们现在开始!
如果您需要使用线程模块,则希望主要睡一会儿。如果子线程未结束,则主线程下方的代码将自动杀死。当然,这也是线程模块的缺点。不管子过程是否结束,一旦主线继续延续,子线程都会被杀死。
如果您使用螺纹模块,只要您不将子线程设置为后卫过程,则在执行主机后也会杀死子线程。
您的问题有点奇怪。其他人问执行主线程时如何被杀死。
举个例子:
导入线程
从时间进口睡眠,ctime
def loop0():
打印“启动循环0:”,ctime()
睡眠(4)
打印“循环0完成:',ctime()
def loop1():
打印“启动循环1:”,ctime()
睡眠(2)
打印“循环1完成:',ctime()
def main():
打印“从:”,ctime()
thread.start_new_thread(loop0,())
thread.start_new_thread(loop1,())
睡眠(6)
打印“全部执行:”,ctime()
如果__name__ =='__ main __':
main(main(main(主)
这是Python核心编程中的一个例子。主线程将等待6秒钟。6秒后,继续遵循主程序(即主线程)。永不结束。
由于python的臭名昭著的吉尔。
那吉尔是什么?为什么有吉尔?多线程真的是鸡排吗?可以去除吉尔吗?如果有这些问题,我们在一起看着,同时需要一点耐心。
是多线鸡肋骨吗?让我们先进行实验。实验非常简单。它是为了减少“ 1亿”的数量,并将其减少到0程序。如果我们使用单个线程执行,那么完成时间是什么?将使用多线程?显示我的代码
单线
在我的4台CPU计算机中,在单个线程上花费的时间为6.5秒。有人可能会问,线程在哪里?实际上,当任何程序运行时,默认情况下将有一个主线程执行。(关于线程和过程不会在这里扩展,我将分别打开一篇文章)
多线程
创建两个子线程T1和T2,每个线程执行5000万次执行,并且在执行两个线程后,主线程终止程序操作。结果,在合作中执行了两个线程,但合作执行了6.8秒,但放慢了速度从理论上讲,这两个线程同时在两个CPU上运行。时间应该减半,但现在没有减少。
是什么导致多线程不现实和缓慢?
原因在于吉尔。在Cpython解释器(Python语言中的主流解释器)中,有一个全局的解释锁。当解释器解释Python代码时,这意味着该锁首先意味着任何时间,可能只有一个线程执行代码。如果其他线程想获得CPU执行代码指令,则必须先获得此锁定。如果锁被其他线程占据,则线程只能等到锁的线程被锁的线占据,释放锁可能会执行代码指令。
因此,这就是为什么两个线程在一起慢的原因,因为同时,只有一个线程正在运行,而其他线程只能等待。即使是多核CPU也可以在同一Timethe执行代码上同时使用多个线程“并行”,因为多线程切换和锁定机制处理(获取锁,释放锁等),因此可以交替执行。参与其中,因此多线程执行不是快速且缓慢。
吉尔什么时候发布?
当线程遇到I/O任务时,将发布GIL。当CPU结合线程执行100个口译器(ticks)(ticks)(ticks)(ticks)(可以大致认为是Python虚拟机)时,GIL也将是发布。您可以通过设置步骤长度来检查步骤的步骤。
为什么Cpython的解释器设计这样?
多线程是适应现代计算机硬件的高速开发,以充分利用多核处理器的产品。通过多线程,可以有效地使用CPU资源。Python出生于1991年。在Timethe Server 32 Core 64g内存并不常见
但是,多线程存在问题。如何解决共享数据的同步和一致性问题,因为当多个线程访问和共享数据时,可能会有两个线程同时修改一个数据情况。如果没有合适的机制来确保Dathathen的一致性最终导致异常,因此Python的父亲具有全球线锁。无论您是否与数据有同步问题,无论如何,您都可以将其切成全局锁以确保数据安全性。这是多线程鸡排的原因,因为它没有对安全性的良好的控制数据,但以简单而粗鲁的方式解决。
该解决方案放置在1990年代。实际上,没有问题。毕竟,当时的硬件配置仍然非常简单。单个核心CPU仍然是主流。run,不涉及线程的上下文切换,但是效率高于多线程(在多核环境中,此规则不适用)。因此,它不适用使用GIL确保数据的一致性和安全性所必需。至少在当时这是一种非常低的成本实施方法。
删除吉尔是否可行?
有人确实做了很多事情,但结果令人失望。1999年,两个伙伴格雷格·斯坦(Greg Stein)和马克·哈蒙德(Mark Hammond)创建了一个python分支,该分支将吉尔(Gil)删除并用更可变的数据结构取代了更细腻的数据结构。在单线条件下,Python的速度速度较慢。
Python的父亲说:基于上述考虑,GIL在不必花费太多精力的情况下没有很大的价值。
创建的子线程默认为非守卫者。
NON -GUARDIAN:当主线程结束后,子线程继续运行,两者不会互相影响。
子线程是监护线程:当主线程结束后,子线程已经结束(无论子线程工作是否完成)。
联接的作用是线程同步,这是等待子线程的主线程的末端(主螺纹在没有结束的情况下完成,障碍物等待和子线程一起完成)。
我相信您目前已经了解了两个问题。
当主线程未添加时,主线程已经结束,因此命令提示符发布,但是子线程尚未结束。3/5秒后,打印了字符串。添加加入后,两个子线程和其他子线程在结束前结束,因此最终出现了。
理解的确有点偏见。Guardian表示子线程守护主线程,如果您死亡,您会死亡。
Python提供了两个模块,以实现多线程和螺纹。线程有一些缺点。它已经在螺纹中构成。为了不浪费您和时间,我们可以直接学习线程。
继续改变上面的示例,介绍线索以同时播放音乐和视频:
#coding = utf-8import螺纹从时间导入ctime,sleepdef music(func):对于我在范围(2)中的i:打印“我在听%s”%s“%s”%s”(func())))))
睡眠(1)DEF MOVE(func):对于i在范围(2)中:打印“我在%s!%s”%(func,ctime()))
睡眠(5)
线程= []
t1 = threading.thread(target = music,args =(u'love sale'),)),)
threads.append(T1)
t2 = threading.thread(target = move,args =(u'avatar',))
threads.append(t2)如果__name __ =='__ main __':对于线程中的t:
t.setdaemon(true)
t.start()prop“全%s”%ctime()
导入线程
首先导入螺纹模块,这是使用多线程的先决条件。
线程= []
t1 = threading.thread(target = music,args =(u'love sale'),)),)
threads.append(T1)
创建线程数组,创建一个线程T1,使用threading.thread()方法,调用Music方法target =此方法中的音乐,并且ARGS方法传递音乐的参数。将创建的线程T1输入到线程数组中。
然后以相同的方式创建线程T2,然后将T2安装到线程数组中。
对于线程中的t:
t.setdaemon(true)
t.start()
最后,通过阵列进行循环。(阵列装有两个螺纹T1和T2)
setdaemon()
setdaemon(true)将线程声明为守护线。必须在开始()方法调用之前设置它。如果未设置为“后卫线程”程序,它将被无限地悬挂。在启动子线程后,父螺纹继续执行。当父线程执行最后一个语句时,最后一个语句“全范围s”%ctime(),没有等待子线程,sub -thread结束了。
开始(开始)
启动线程活动。
操作结果:
=================================================
我活着喜欢买卖
从执行结果的角度来看,子线程(muisc,move)和print(打印“全米s”%ctime())全部启动,但是由于主线程执行结束,所以SUB- 线程已终止。
继续调整程序:
...如果__name__ =='__ main__':对于线程中的t:
t.setdaemon(true)
t.start()
t.join()prop“全%s”%ctime()
我们仅在上面的程序中添加了一个Job()方法,才能等待线程终止。JOIN()的作用是,该子线程的母线将始终在子线程运行之前被阻止。
注意:JOIN()方法的位置不在for循环之外,这意味着在执行主过程之前,必须在for Cycle中架设两个过程。
操作结果:
=================================================
我在听爱买卖。THU APR 17 13:04:11 2014我在头像!THU APR 17 13:04:11 2014I正在听爱销售。thu Apr 17 13:04:16 2014年全天候全部17 13:04:21 2014
从执行结果可以看出,音乐和移动是同时开始的。
开始时间为4分11秒钟,直到主过程称为4分22秒,总时间为10秒。从单个线程减少2秒钟,我们可以调整音乐睡眠时间()到4秒。
... def music(func):对于我在范围(2)中:打印“我在听%s。%s”%(func,ctime())
睡眠(4)
Em
子线程开始11分27秒,主线程运行11分37秒。
尽管每首音乐的歌曲都从1秒延伸到4,但脚本以多行方式运行,总时间没有改变。
过程和线程
这两个概念属于操作系统。我们经常听到,但很少有人可以研究其含义。对于工程师,仍然有必要理解两者之间的定义和差异。
首先,该过程可以被视为CPU执行的特定任务。在操作系统中,由于CPU非常快,因此比计算机中的其他设备快得多。例如,内存,磁盘等,如果CPU一次仅执行一项任务,则会导致CPU等待这些设备很多,因此操作效率非常低。为了提高计算机的运行效率,机器的技能被挤压了尽可能出去。CPU是查询。换句话说,它一次只执行一个任务,并且在执行一小块片段以执行其他任务后立即切换。
因此,在早期的单眼机器中,计算机似乎也可以同时使用。我们可以在听这首歌时浏览互联网,而且我们不会感到口吃。但实际上,这是CPU旋转的结果。在此示例中,聆听歌曲和Internet软件的软件是CPU的独立过程。我们可以简单地了解操作过程。例如,在Android手机中,一个过程将与应用程序启动时的过程相对应。当然,此语句不是完全准确的,并且一个应用程序也可以启动多个进程。
该过程与CPU相对应,线程更针对程序。,我们需要显示歌词的字幕,戏剧的声音和用户的行为,例如是否剪裁歌曲,调整音量等等。因此,我们需要进一步分开CPU,因此在执行当前过程时,它将继续通过旋转同时执行多件事。
该过程中的任务是线程,因此从这个角度来看,过程和线程包括一个关系。一个过程可以包含多个线程。对于CPU,无法直接执行该线程,并且线程必须属于进程。因此,我们知道CPU进程开关转到Switch是执行的应用程序或软件,并且该过程内部的线程切换是特定的执行软件中的任务。
关于过程和线程的经典模型可以解释它们之间的关系。假设CPU是工厂,工厂中有多个研讨会。不同的讲习班对应于不同的生产任务。一些研讨会生产汽车轮胎,有些研讨会产生了汽车骨架。但是,工厂的力量有限,只能满足工厂建筑的使用。
为了使每个人的进度取得进展,工厂需要轮流在每个研讨会中提供电源。这里的研讨会与该过程相对应。
尽管研讨会仅生产一种产品,但有一个以上的过程。车间中可能有几个装配线。特定的生产任务实际上由组装线完成。每条装配线都对应于特定的任务。但是,与此同时,研讨会只能同时执行装配线,因此我们需要研讨会在这些装配线之间切换,并让每个组件统一的生产进度。
车间中的流线自然对应于线程的概念。该模型解释了CPU,过程和线程之间的关系。实际原理确实是相同的,但是CPU中的情况比现实中的研讨会要复杂得多。由于流程和CPU,他们面临的情况在真实的情况下发生了变化。时间。研讨会中的流线为X,下一刻可能变成Y。
在理解线程和过程的概念之后,了解计算机的配置也很有帮助。例如,当我们购买计算机时,我们经常遇到一个术语,也就是说,该计算机的CPU来自某个核和某些线程。例如,我那年购买的第一个笔记本是4个核心和8个线程。这实际上是该计算机的CPU具有4个计算核心,但是上行技术的使用可以将物理核模拟为两个逻辑。同一时间,但实际上4个内核是虚拟核心模拟。
一个问题是为什么它是4个核和8个线程,而不是4个核心和8个进程?因为CPU不直接执行该过程,而是在过程中执行某个线程。直接,只有装配线才能产生零件。研讨会更负责资源的部署,因此教科书中有一个非常经典的单词要解释:该过程是资源分配的最小单位,线程是最小的。CPU调度单位。
启动线程
Python为我们提供了一个完整的线程库。通过它,我们可以轻松地创建线程以执行多线程。
首先,我们在线程中介绍线程,这是线程类。我们可以通过创建线程实例来执行多线程。
从线程导入线程t =线程(target = func,name ='therad',args =(x,y))t.start()
为了简要解释其用法,我们已将三个参数分为三个参数,即目标,名称和args。从名称来看,我们可以猜测它们的含义。第一个是目标,这是一种引入的方法,即我们想要多线程执行的方法。名称是我们新创建的线程的名称。可以省略此参数。如果省略了,系统将为它设置一个系统名称。当我们执行python时,线程名称为主题,我们可以通过线程名称区分。ARGS是一个将传递到目标函数的参数。
让我们举一个经典的例子:
导入时间,线程#新线程执行代码:def loop(n):print('thread%s正在运行...'%three.current_thread()。名称):%s%s'%(threading.current.current_thread())。t = threading.thread(target = looop,name ='loopthread',args =(10,))print('thread%s结束。'%螺纹.current_thread()。名称)
我们创建了一个非常简单的循环函数来执行一个循环以打印数字。每次打印一个数字之后,此线程将睡觉5秒,因此我们看到的结果应每5秒钟超过5秒钟。
让我们在Jupyter中执行它:
从表面上看,这个结果很好,但实际上存在问题。有什么问题?输出的顺序不正确。为什么主要线程打印第一个数字0?另一个问题是,由于主线程已经结束,为什么未结束的Python进程仍在向外打印?
因为线程是独立的,对于主线程,它不会在执行t.start()之后留下操作结束后的子线程,我们可以将T.Join()的线添加到代码中以实现此目标。
t.start()
加入操作允许主线程在加入处挂起,直到继续执行之前的子线程执行结束。我们添加了JOIN运行结果:
这是我们期望的,我们将在执行子线程结束后继续。
让我们再次查看第二个问题。为什么当主线程结束时,子线程继续运行,而Python进程未退出?这是因为我们默认情况下创建了用户 - 级线程。对于进程,它将等待所有用户 - 级线程在执行所有用户 - 级线程后退出。这里有一个问题。如果我们创建一个线程以尝试从接口获取数据,则因为接口尚未返回,当前过程是否会永远等待?
这显然是不合理的,因此为了解决此问题,我们可以将创建的线程设置为守卫线程。
监护人线
监护人线是守护程序线程。它的英语文字翻译实际上是背景中的背景,因此我们也可以理解背景线程,这更方便地理解。DAEMON线程与用户线程级别不同。该过程不会主动等待执行守护程序线程。当所有用户 - 级线程的执行将退出时。
我们传递守护程序= true参数,将创建的线程设置为背景线程:
t = threading.thread(target = looop,name ='loopthread',args =(10,),守护程序= true)
这样,我们再次看到的结果是:
在这里要注意的一件事是,如果您在Jupyter中运行,您将看不到这样的结果。因为Jupyter本身就是一个过程,对于Jupyter中的单元格,它始终由用户级别的线程生存下来,因此该过程将会不退出。因此,如果您想查看这种效果,则只能通过命令行执行Python文件。
如果我们想等待此子线程结束,我们必须传递加入方法。加上添加,为了防止子线程锁定,我们还可以在joih中设置超时,也就是说,是最长的等待时间,等待时间到达时,我们将不再等待。
例如,当我设置的超时连接等于5时,屏幕上只有5个数字。
此外,如果未设置为背景线程,尽管超时也很有用,但该过程仍将等待所有子线程结束。因此,屏幕上的输出结果将如下:
尽管主线程继续执行并结束,但子线程仍在运行,直到子线程运行为止。
这里有一个关于加入设置的坑。如果我们只有一个线程等待,如果我们有多个线程,我们将使用一个周期来设置它们。每个线程计算的启动时间是在上一个线程的末尾,随着时间的推移,它将等待所有线程暂停,然后它们将它们终止。
例如,我创建了3个线程:
ths = []对于i在范围(3)中的i:t = threading.thread(target = looop,name ='loopthread' + str' + str(i),args =(10,),daemon = true)ths.append(t)对于t t ths:t.start()for t ths in ths:t.join(2)
屏幕上输出的结果是:
所有线程都存活了6秒。
总结
在今天的文章中,我们简要了解操作系统中线程和过程的概念,以及如何在Python中创建线程以及创建线程后相关使用。
多语言中的多线程至关重要,在许多情况下将使用多线程。界面。由于所有这些都涉及UI,因此不可避免地需要一个单独的渲染页面,另一个线程负责准备数据和执行逻辑。因此,Multi -Threading是专业程序员无法解决的主题,并且它是一个主题,并且是一个主题也是必须掌握的内容之一。
结论:以上是首席CTO注释为每个人编制的Python线程的相关内容答案。希望它对您有所帮助!如果您解决了问题,请与更多关心此问题的朋友分享?