孤荷凌寒自学python第三十八天初识python的线程控制

(完整学习过程屏幕记录视频地址在文末,手写笔记在文末)

一、线程

在操作系统中存在着很多的可执行的应用程序,每个应用程序启动后,就可以看着是一个进程,当打开WINDOWS任务管理器时,在任务管理器的进程选项卡中列出的就是一个一个的进程,基本上每个应用程序都对应着至少一个进程。

在同一进程中,也许同时在做着不止一件事情,比如在向程序界面上显示信息和接受信息的同时,程序也在和远端服务器通信读取数据,则这儿至少有两个线程运行在同一个进程中。

我的简单理解是,在同一个操作系统的进程中,可以同时执行多个线程的任务。

二、threading模块

threading模块是Python 中主要的线程控制模块。

使用threading模块前必须先声明引用:

import threading

三、threading模块的常见子类与属性和方法

1

threading.activeCount()

执行此方法返回当前进程下所有活动的线程总数。

2

threading.enumerate()

此方法直接返回一个 迭代器,迭代器中包含了,所有当前进程下的所有线程的信息。

在实际测试中,发现在循环打印时,总是不打印出第0个线程的信息,没有核准原因。

见后面的测试代码与结果。

3

threading.Thread

这是threading模块下的子模块(类),特别注意Thread模块的首字母是大写的。这是最容易疏忽之处。

四、获取或定义得到一个threading.Thread线程对象

可以通过以下方式得到threading.Thread线程对象

1.第一种:

thread对象=threading.Thread(target=要让新线程执行的函数名 , args=这个函数需要的参数组成的元组)

测试代码:

def f1(n):

strtime=str(datetime.now())

print('线程' + n + '正在运行中....线程启动于:' +strtime)

t=threading.Thread(target=f1,args=('t1',))

上面代码中,我创建了一个线程对象 t ,这个线程如果启动,将执行函数f1定义好的内部代码块。

Thread类的建构代码(初始化函数)中,要求传递的两个实参,只能按【关键字参数】形式传递进去。

2.第二种

thread对象=threading.Thread(target=要调用的作为函数用的类名(此类的初始化方法需要的参数列表))

测试代码:

class myt(object):

def __init__(self,n):

self.n=n

def __call__(self):

strtime=str(datetime.now())

print('线程' + self.n + '正在运行中....线程启动于:' +strtime)

t=threading.Thread(target=myt('t1'))

这种方式中,线程t启动后,将执行的是一个可以当着函数来调用的类myt.

myt是一个可以被 当着函数来使用的类,因为在类的内部代码块中定义有:__call__()私有方法。

与第一种方式不同的地方在于,这次只向Thread初始化方法传递了一个关键字实参target。

3.第三种方式

直接写一个新的继承自threading.Thread类的子类,然后,用新的类来初始化得到一个thread对象。

测试代码:

class myt(threading.Thread):

def __init__(self,n):

threading.Thread.__init__(self)

self.n=n

def run(self):

strtime=str(datetime.now())

print('线程' + self.n + '正在运行中....线程启动于:' +strtime)

t=myt('t1')

首先建构了一个继自threading.Thread的类 myt,这个类的特点有:

(1)在子类的__init__()方法中,必须 先调用父类的__init__()方法,在我的上机测试过程中(见过程屏幕录像,这儿反复出错,结果发现就是没有先调用父类的__init()__方法,引发的错误。

而原因在测试当时没有思考出来,所以大家在我的测试屏幕录像中可以看到没有想明白,现在思考下,发现可能是因为在threading.Thread类本身的__init__()中要执行非常重要的初始化操作,才能保证thread本类实例化后的对象功能可用,我找到了threading.Thread类本身的__init__()方法的代码如下:

def __init__(self, group=None, target=None, name=None,

args=(), kwargs=None, *, daemon=None):

"""Thisconstructor should always be called with keyword arguments. Arguments are:

*group* should be None; reserved forfuture extension when a ThreadGroup

class is implemented.

*target* is the callable object to beinvoked by the run()

method. Defaults to None, meaningnothing is called.

*name* is the thread name. By default,a unique name is constructed of

the form "Thread-N" where Nis a small decimal number.

*args* is the argument tuple for thetarget invocation. Defaults to ().

*kwargs* is a dictionary of keywordarguments for the target

invocation. Defaults to {}.

If a subclass overrides theconstructor, it must make sure to invoke

the base class constructor (Thread.__init__())before doing anything

else to the thread.

"""

assert group is None, "groupargument must be None for now"

if kwargs is None:

kwargs = {}

self._target= target

self._name =str(name or _newname())

self._args =args

self._kwargs= kwargs

if daemon is not None:

self._daemonic= daemon

else:

self._daemonic= current_thread().daemon

self._ident= None

self._tstate_lock= None

self._started= Event()

self._is_stopped= False

self._initialized= True

# sys.stderr is notstored in the class like

# sys.exc_infosince it can be changed between instances

self._stderr= _sys.stderr

# For debugging and_after_fork()

_dangling.add(self)

以上代码可以证明我的猜测是正确的,因此在测试屏幕录像中我没有想通的问题现在基本上有答案了,当然正确与否希望大家批评指正。

(2)在定义继承自threading.Thread类的子类中,__call__()方法 需要被 改名为 run()方法。

五、threading.Thread对象的主要属性与方法有:

1 name属性

此属性可读写,用以设置和获取线程对象的名称。

2 getName()方法

用于获取线程对象的名称。

3 setName()方法

用于设置线程对象的名称。

4 ident

此属性是只读的,获取线程对象的标识码,标识码是数字。

5 is_alive()  isAlive()

这两个方法用于判断线程对象是否正在运行(存活),返回布尔对象。

6 join()

这是线程对象非常 重要 的方法,此方法有一个可选 形参 timeout

执行线程的此方法后,会将调用 此线程的上级线程 阻塞,然后等待此线程执行完成,如果为join()方法设置了timeout时间,那么从此线程开始执行起计时,达到timeout指定的时间限额时,将自动解除对上级线程的阻塞。

在今天 的测试过程中,没有着重测试此方法的具体功用,理解可能不完全准确。

7 start()

线程执行此方法后,线程就开始执行指定任务,同时线程的isAlive标识将显示为True

此外,我没有发现线程有stop()方法,目前也没有研究到中止指定线程执行的其它方法。

测试代码一 :

importthreading

from datetimeimport datetime

intcount=3

class myt(object):

def __init__(self,n):

self.n=n

def __call__(self):

strtime=str(datetime.now())

print('线程' + self.n + '正在运行中....线程启动于:' +strtime)

def main():

threads=[]

x=range(intcount)

for n in x:

t=threading.Thread(target=myt('t' + str(n)))

#if n==1:

#    t.setDaemon(True)

t.name='t' + str(n)

threads.append(t)

for n in x:

threads[n].start()

#print(threading.activeCount())

for item inthreading.enumerate():

print(item)

print('--------')

for item inthreads:

print(item)

print(threads[0].isAlive())

for n in x:

threads[n].join()

if __name__=='__main__':

main()

执行结果:

线程t0正在运行中....线程启动于:2018-08-1617:31:08.939618

线程t1正在运行中....线程启动于:2018-08-1617:31:08.939618

线程t2正在运行中....线程启动于:2018-08-1617:31:08.940647

<_MainThread(MainThread, started 4436)>

<Thread(t1, stopped 2444)>

<Thread(t2, stopped 8676)>

--------

<Thread(t0, stopped 3188)>

<Thread(t1, stopped 2444)>

<Thread(t2, stopped 8676)>

False

测试代码二:

importthreading

fromdatetime import datetime

intcount=3

class myt(threading.Thread):

def __init__(self,n):

threading.Thread.__init__(self)

self.n=n

def run(self):

strtime=str(datetime.now())

print('线程' + self.n + '正在运行中....线程启动于:' +strtime)

def main():

threads=[]

x=range(intcount)

for n in x:

t=myt('t' + str(n))

#if n==1:

#    t.setDaemon(True)

t.name='t' + str(n)

threads.append(t)

for n in x:

threads[n].start()

#print(threading.activeCount())

for item inthreading.enumerate():

print(item)

print('--------')

for item inthreads:

print(item)

print(threads[0].isAlive())

for n in x:

threads[n].join()

if __name__=='__main__':

main()

执行结果:

线程t0正在运行中....线程启动于:2018-08-1617:32:36.893226

线程t1正在运行中....线程启动于:2018-08-1617:32:36.894223

线程t2正在运行中....线程启动于:2018-08-1617:32:36.895221

<_MainThread(MainThread, started 8884)>

<myt(t2, stopped 8940)>

--------

<myt(t0, stopped 7152)>

<myt(t1, stopped 8744)>

<myt(t2, stopped 8940)>

False

注意执行结果中,threading.enumerate()方法返回的迭代器在循环取出对象时,总没有完整打印,且有空行。这点没有思考出答案。搜索网络没有找到答案,还有待继续思考,并恳请高手予以指点。

——————————

今天整理的学习笔记完成,最后例行说明下我的自学思路:

根据过去多年我自学各种编程语言的经历,认为只有真正体验式,解决实际问题式的学习才会有真正的效果,即让学习实际发生。在2004年的时候我开始在一个乡村小学自学电脑 并学习vb6编程语言,没有学习同伴,也没有高师在上,甚至电脑都是孤岛(乡村那时还没有网络),有的只是一本旧书,在痛苦的自学摸索中,我找到适应自己零基础的学习方法:首先是每读书的一小节就作相应的手写笔记,第二步就是上机测试每一个笔记内容是否实现,其中会发现书中讲的其实有出入或错误,第三步就是在上机测试之后,将笔记改为电子版,形成最终的修订好的正确无误的学习笔记。

通过反复尝试错误,在那个没有分享与交流的黑暗时期我摸黑学会了VB6,尔后接触了其它语言,也曾听过付费视频课程,结果发现也许自己学历果然太低,就算是零基础的入门课程,其实也难以跟上进度,讲师的教学多数出现对初学者的实际情况并不了解的情况,况且学习者的个体也存在差异呢?当然更可怕的是收费课程的价格往往是自己难以承受的。

于是我的所有编程学习都改为了自学,继续自己的三步学习笔记法的学习之路。

当然自学的最大问题是会走那么多的弯路,没有导师直接输入式的教学来得直接,好在网络给我们带来无限搜索的机会,大家在网络上的学习日志带给我们共享交流的机会,而QQ群等交流平台、网络社区的成立,我们可以一起自学,互相批评交流,也可以获得更有效,更自主的自学成果。

于是我以人生已过半的年龄,决定继续我的编程自学之路,开始学习python,只希望与大家共同交流,一个人的独行是可怕的,只有一群人的共同前进才是有希望的。

诚挚期待您的交流分享批评指点!欢迎联系我加入从零开始的自学联盟。

这个时代互联网成为了一种基础设施的存在,于是本来在孤独学习之路上的我们变得不再孤独,因为网络就是一个新的客厅,我们时刻都可以进行沙龙活动。

非常乐意能与大家一起交流自己自学心得和发现,更希望大家能够对我学习过程中的错误给予指点——是的,这样我就能有许多免费的高师了——这也是分享时代,社区时代带来的好福利,我相信大家会的,是吧!

根据完全共享的精神,开源互助的理念,我的个人自学录制过程是全部按4K高清视频录制的,从手写笔记到验证手写笔记的上机操作过程全程录制,但因为4K高清文件太大均超过5G以上,所以无法上传至网络,如有需要可联系我QQ578652607对传,乐意分享。上传分享到百度网盘的只是压缩后的720P的视频。

我的学习过程录像百度盘地址分享如下:(清晰度:1280x720)

链接:https://pan.baidu.com/s/1n00vs2zpHiMCCf5eqykGrg

提取码:bgu2

Bilibili:

https://www.bilibili.com/video/av38088874/

喜马拉雅语音笔记:

https://www.ximalaya.com/keji/19103006/144900713

孤荷凌寒自学python第三十八天初识python的线程控制的更多相关文章

  1. 孤荷凌寒自学python第三十九天python 的线程锁Lock

    孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...

  2. 孤荷凌寒自学python第三十七天python的文件与内存变量之间的序列化与反序列化

    孤荷凌寒自学python第三十七天python的文件与内存变量之间的序列化与反序列化 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.什么是序列化与反序列化 序列化是指将内存中的数据进行指 ...

  3. 孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容

     孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.打开文件后,要务必记得关闭,所以一般的写法应当 ...

  4. 孤荷凌寒自学python第三十四天python的文件操作对file类的对象学习

     孤荷凌寒自学python第三十四天python的文件操作对file类的对象学习 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.close() 当一个file对象执行此方法时,将关闭当前 ...

  5. 孤荷凌寒自学python第三十三天python的文件操作初识

     孤荷凌寒自学python第三十三天python的文件操作初识 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天开始自学python的普通 文件操作部分的内容. 一.python的文件打开 ...

  6. 孤荷凌寒自学python第三十一天python的datetime.timedelta模块

     孤荷凌寒自学python第三十一天python的datetime.timedelta模块 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) datetime.timedelta模块是一个表示 ...

  7. 孤荷凌寒自学python第三十天python的datetime.datetime模块

     孤荷凌寒自学python第三十天python的datetime.datetime模块 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) datetime.datetime模块包含了:datet ...

  8. 孤荷凌寒自学python第三天 初识序列

    孤荷凌寒自学python第三天 初识序列 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Python的序列非常让我着迷,之前学习的其它编程语言中没有非常特别关注过序列这种类型的对象,而pyt ...

  9. 孤荷凌寒自学python第八十六天对selenium模块进行较详细的了解

    孤荷凌寒自学python第八十六天对selenium模块进行较详细的了解 (今天由于文中所阐述的原因没有进行屏幕录屏,见谅) 为了能够使用selenium模块进行真正的操作,今天主要大范围搜索资料进行 ...

随机推荐

  1. Poj(2312),坦克大战,BFS的变形

    题目链接:http://poj.org/problem?id=2312 挺有趣的一道题目,然而很容易WA,我就WA了一次,虽然我Debug的时候已经知道哪里出问题了,就是比如说我搜到B和E时,从B搜第 ...

  2. js 动态创建标记

    innerHTML:一旦使用了这个属性,它的全部内容都要被替换掉.且不会返回任何对刚插入的内容的引用 与document.write()方法一样,innerHTML属性也是HTML专有属性,不能用于任 ...

  3. lambda函数,内置map()函数及filter()函数

    8.1 lambda函数 作用及意义:  1.没必要专门定义函数,给函数起名,起到精简的效果  2.简化代码的可读性 def ds(x): return 2 * x + 1 ds(5) ---11 g ...

  4. vue-router 实现分析

    我们分别从不同的视角来看 vue-router. http://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=2247485737&idx ...

  5. BZOJ2752: [HAOI2012]高速公路(road)(线段树 期望)

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1820  Solved: 736[Submit][Status][Discuss] Descripti ...

  6. CentOS 6.5通过yum安装 MySQL-5.5

    1.安装mysql-5.5的yum源 rpm -ivh http://repo.mysql.com/yum/mysql-5.5-community/el/6/x86_64/mysql-communit ...

  7. 交换机基础配置之单交换机划分vlan

    我们以以上拓扑图为例 pc0的IP地址为:192.168.1.1 pc1的ip地址为:192.168.1.2 两台主机在同一网段,相互ping是能ping通的 我们的目的是在单交换机上划分两个vlan ...

  8. bootloader svc 模式

    bootloader 和操作系统都是工作在svc模式下 /* * set the cpu to SVC32 mode */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0, ...

  9. 云计算之KVM虚拟化实战

    1 基础环境规划 1.1 主机环境规划 系统版本 主机名 IP地址 内存 磁盘 CentOS6.9 kvm-node1 10.0.0.200 2G 20G CentOS6.9 kvm-node2 10 ...

  10. 谈一谈你对js线程的理解

    js线程:javascript是单线程的,所有任务都需要排队,这些任务分为同步任务和异步任务,单线程上有一个主线程任务.同步任务必须再主线程上排队进行,而异步任务(类似于点击事件)必须在主线程上的任务 ...