Python - 多线程(一)线程的创建,管理,停止

先简单介绍一下线程的概念:
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
说白了就是线程就是完成某个特定功能的一段代码,但线程的开销要比进程小的多。一个Python程序至少有一个线程,那就是Python的主线程,程序启动后由Python解释器负责创建主线程,程序结束时由Python解释器来负责结束主线程。

1.简单介绍threading模块的常用函数:

threading.active_count()#返回当前处于活动状态的线程个数
threading.current_thread()#返回当前的Thread对象
threading.main_thread()#返回主线程对象,主线程是Python解释器启动的线程
threading.currentThread()#返回当前的线程变量。
threading.enumerate()#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount()#返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

代码示例:

import threading

#当前处于活动状态的线程的个数
print(threading.active_count())
#当前线程的名字
print(threading.current_thread().name)
#主线程的名字
print(threading.main_thread().name)
#当前的线程变量
print(threading.currentThread())
#一个包含正在运行的线程的list
print(threading.enumerate())

运行结果:

1
MainThread
MainThread
<_MainThread(MainThread, started 140737184076736)>
[<_MainThread(MainThread, started 140737184076736)>]

结果看出,当前线程为Python的主线程,名字为MainThread

2.创建线程

  • 创建一个可执行的线程需要线程对象和线程体
  • 线程对象:threading模块线程类Thread所创建的对象
  • 线程体:线程的执行函数,线程启动会执行该函数,线程所处理的代码是在线程体中编写的

创建线程对象:

class Thread(_Verbose)

    __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)

    *group *:group参数必须为空,参数group是预留的,用于将来扩展;
     
      参数args和kwargs分别表示调用target时的参数列表和关键字参数。

    *target *: 参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行

    *name *: 参数name是线程的名字。默认值为“Thread - N“,N是一个数字。

    *args *:传递给线程函数target的参数, 他必须是个tuple类型.

    *kwargs *:kwargs表示关键字参数。字典类型

创建线程体的方法1:自定义函数为线程体

import threading
import time

#自定义线程函数
#线程方法
def threading_body():
    #当前对象线程
    t = threading.current_thread()
    for i in range(1,6):
        #当前线程名
        print("第{0}次执行线程 {1}".format(i,t.name))
        #线程休眠
        time.sleep(1)
    print("线程{0}执行完成".format(t.name))

def main():
    #创建线程t1对象
    t1 = threading.Thread(target=threading_body,name='线程1')
    #启动线程1
    t1.start()
    # 创建线程t2对象
    t2 = threading.Thread(target=threading_body,name='线程2')
    #启动线程2
    t2.start()

if __name__ == '__main__':
    main()

执行结果:

1次执行线程 线程11次执行线程 线程22次执行线程 线程12次执行线程 线程23次执行线程 线程13次执行线程 线程24次执行线程 线程14次执行线程 线程25次执行线程 线程15次执行线程 线程2
线程线程1执行完成
线程线程2执行完成

若没有进行线程休眠,执行结果如下:

1次执行线程 线程12次执行线程 线程13次执行线程 线程14次执行线程 线程15次执行线程 线程1
线程线程1执行完成
第1次执行线程 线程22次执行线程 线程23次执行线程 线程24次执行线程 线程25次执行线程 线程2
线程线程2执行完成
  • 由此可见线程休眠是多么的重要,线程执行时交替执行并没有一定的执行顺序。
  • 两个线程都循环了5次,线程1和线程2他们运行同一个函数,因此可以通过线程抢夺的性质和线程休眠来实现。
  • 使用time.sleep()是为了让两个线程运行的顺序成为(以i为代表)1,1,2,2,3,3,4,4,5,5。当线程1或线程2抢到线程时,执行函数,执行到sleep(),这个线程就会休眠,这时就剩另外一个线程来运行,另一个线程执行完同样休眠。一个线程运行一次就休眠,让给其他没运行过的线程让他们来运行,从而使他们可以几个线程一循环,在一定程序上会阻碍该线程获得 CPU 调度。。

创建线程体的方法2:继承重写run()方法,run()方法作为线程

import threading
import time

class MyThread(threading.Thread):# 继承父类threading.Thread
    def __init__(self, name):
        # 重写threading.Thread初始化内容
        # threading.Thread.__init__(self)
        # threading.Thread.__init__(self) = super().__init__()
        super().__init__()
        self.name = name
    # 把要执行的代码写到run函数里面,线程在创建后会直接运行run函数
    def run(self):
        for i in range(1, 6):
            print("第%s次执行线程%s,当前线程%s" % (i, self.name, threading.current_thread().name))
            # 线程休眠
            time.sleep(1)
        print("{0}执行完成".format(self.name))
def main():
    # 创建线程对象1
    t1 = MyThread("线程1")
    # 启动线程1
    t1.start()
    # 创建线程2
    t2 = MyThread("线程2")
    # 启动线程2
    t2.start()

if __name__ == '__main__':
    main()

后台执行结果:

1次执行线程线程1,当前线程线程11次执行线程线程2,当前线程线程22次执行线程线程1,当前线程线程12次执行线程线程2,当前线程线程23次执行线程线程1,当前线程线程13次执行线程线程2,当前线程线程24次执行线程线程1,当前线程线程14次执行线程线程2,当前线程线程25次执行线程线程1,当前线程线程15次执行线程线程2,当前线程线程2
线程1执行完成
线程2执行完成
  • start()方法调用run()方法,而run()方法调用函数
  • start()方法是每个线程对象必需至多调用一次,当超过1次的多次调用时,则会抛出错误;在一个单独的线程控制中,它将会调用run()方法
  • run()方法可以在子类中重定义。标准run()方法调用回调对象作为参数传递给目标对象的构造函数。

3.线程管理

#线程管理
‘’’
等待线程结束
当前线程调用t1线程的join()方法时则阻塞当前线程,等待t1线程的结束,如果t1线程结束或等待超时,则当前线程回到活动状态继续执行

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name):
        # 继承父类
        # threading.Thread.__init__(self)
        # threading.Thread.__init__(self) = super().__init__()
        super().__init__()
        self.name = name

    # 继承重写run()方法:
    def run(self):
        for i in range(3):
            print("第%s次执行线程%s,当前线程%s" % (i, self.name, threading.current_thread().name))
            # 线程休眠
            time.sleep(1)
        print("{0}执行完成".format(self.name))

def main():
    print("主线程%s开始" % (threading.current_thread().name))
    # 创建线程
    t1 = MyThread("线程1")
    t2 = MyThread("线程2")
    # 启动线程
    t1.start()
    t2.start()
    # 阻塞主线程,等子线程结束
    t1.join()
    t2.join()
    print("主线程%s结束" % (threading.current_thread().name))

if __name__ == '__main__':
    main()

后台执行结果:

主线程MainThread开始
第0次执行线程线程1,当前线程线程10次执行线程线程2,当前线程线程21次执行线程线程1,当前线程线程11次执行线程线程2,当前线程线程22次执行线程线程1,当前线程线程12次执行线程线程2,当前线程线程2
线程2执行完成线程1执行完成

主线程MainThread结束

怎么证明主线程让阻塞了呢,可以将t1.join()这行代码注释掉,执行结果如下:

主线程MainThread开始
第0次执行线程线程1,当前线程线程10次执行线程线程2,当前线程线程2
主线程MainThread结束
第1次执行线程线程1,当前线程线程11次执行线程线程2,当前线程线程22次执行线程线程1,当前线程线程12次执行线程线程2,当前线程线程2
线程2执行完成
线程1执行完成
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值