python 线程编程 Treading

本文介绍了Python中的线程编程,包括线程之间的关系、如何创建和运行线程、线程的等待与守护、线程间通信及同步机制,如锁、信号量和队列的应用。通过实例讲解了线程的生命周期和并发执行的细节。
该文章已生成可运行项目,

python 线程编程 Treading

记录时间:2019/4/23

问题:

  1. python运行程序和各个线程之间什么关系?
  2. 如何来实例化一个线程?如何运行一个线程?需要注意什么?
  3. 面向对象编程中如何定义一个线程?
  4. 如何在主线程中等待各个子线程完成?
  5. 如何设置守护线程?即主线程运行完之后守护线程自动退出?
  6. 线程之间如何进行最简单的标志位通讯?
  7. 线程中如何定义锁?多个锁如何来使用?
  8. 什么是信号量?如何定义信号量?在什么场景下会使用信号量?
  9. 队列如何使用?可以和线程之间产生什么互动?

解答:

1. python运行的主程序和各个线程之间什么关系?

python中的主程序作为 主线程,而在程序中定义地称为 子线程,多个线程并发执行。

2. 如何来实例化一个线程?如何运行一个线程?需要注意什么?

使用 mythread = threading.Thread( )来声明一个线程; 声明之后使用 .start()方法来启动这个进程; 需要注意,声明时参数必须用元祖的形式传入

  • 使用 thread.Threading( )来声明一个线程
    # 定义线程运行的函数
    def run(n):
        print("task", n)
        time.sleep(2)
        print("task done",n)
    
    # 来实例化线程
    t1 = threading.Thread(target=run, args=("t1",)) # args 必须以元祖的形式传入
    
    # 启动线程
    t1.start()
    

3. 面向对象编程中如何定义一个线程?

要定义一个线程,需要根据 Threading.Thread 作为父类来定义一个子类,在构造函数中将父类重构,并且定义 run() 成员函数,来说明当线程运行的程序。

  • 定义 线程类
    # 定义线程类
    class MyThread(threading.Thread):
        # 构造函数
        def __init__(self,n,sleep_time):
            super(MyThread, self).__init__() # 先来使用 super()完成父类的初始化
            self.n = n
            self.sleep_time = sleep_time
    
        # 定义线程运行的程序
        def run(self):
            print("running task", self.n)
            time.sleep(self.sleep_time)
            print("task done", self.n)
    
    
    # 线程类的实例化
    t1 = MyThread("t1", 2)
    t2 = MyThread("t2", 4)
    
    # 线程对象的运行
    t1.start()
    t2.start()
    

4. 如何在主线程中等待各个子线程完成?

使用 Thread.join() 成员函数,表示等待该线程执行完成再来执行下面的语句

  • 使用 Thread.join() 成员函数来等待循环线程全部执行完成
    # 初始化一个列表,来存储各个定义的线程,方便标记
    obj_t=[]
    # 循环来启动线程
    for i in range(50):
        t = threading.Thread(target=run, args=("t-{}".format(i),))
        t.start()
        obj_t.append(t)
    
    # 一定会按照线程的执行顺序来等待线程执行完成
    for i in obj_t:
        i.join()
    

5. 如何设置守护线程?即主线程运行完之后守护线程自动退出?

在实例化线程t之后,有个 t.setDaemon(True) 函数,在运行前调用,则默认作为主线程的守护线程,相当于主线程的仆人,主线程运行完成,则自动会退出这个守护线程,不论它执行到哪一步。

  • setDaemon() 来设置守护线程
    # 哪怕 run()函数运行很长时间,只要这个主线程退出了,则这个run()的线程一定会被退出
    t = threading.Thread(target=run, args=("t-{}".format(i),))
    t.setDaemon(True)
    t.start()
    

6. 线程之间如何进行最简单的标志位通讯?

来实例一个事件 e = threading.Event(), 然后在各个线程之间进行相互通信,相当于来设置一个全局变量,然后所有线程都可以检测到它的存在。

  • threading.Event() 的用法?
    # 来声明一个事件
    event = threading.Event()
    
    # 设置这个事件的标志位
    event.set()
    
    # 检测这个事件的标志位,如果被设置,则返回 1
    event.is_set()
    
    # 清空这个事件的标志位
    event.clear()
    

7. 线程中如何定义锁?多个锁如何来使用?

使用 lock = threading.Lock() 来实例化一个锁对象,然后就可以用它来开关了

  • 使用 threading.Lock( ) 来防止他们之间的线程冲突
    import  threading
    
    # 在多线程之间定义锁,防止在处理共享数据时发生冲突错误,让其数据处理为原子操作
    def run():
        # 锁的获取
        lock.acquire()
        global  num
        num += 1
        #锁的释放
        lock.release()
    
    lock = threading.Lock()
    num = 1
    for i in range(50):
        t = threading.Thread(target=run, args=())
        t.start()
    
    print(num)
    

8. 什么是信号量?如何定义信号量?在什么场景下会使用信号量?

信号量相当于多把锁,因为线程共享一个代码块,所以,信号量规定一个时间内最多有n个代码块来访问执行这个代码块,使用 semaphore = threading.BoundedSemaphore(n) 来定义信号量,一次最多有n个可以来进行访问;有很多场景下可以使用信号量,比如 socket线程池,python默认会可以开无数个线程,但是线程多了必然会影响性能,所以,在这时候,我们可以通过信号量来规定其最大调用的线程个数

  • 使用threading.BoundedSemaphore(n)
    import threading, time
    
    def run(n):
        # 即最多有五个线程可以访问这个代码块
        semaphore.acquire()
        time.sleep(10)
        print("run the thread: %s\n" % n)
        semaphore.release()
    
    if __name__ == '__main__':
        semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行
        for i in range(22):
            t = threading.Thread(target=run, args=(i,))
            t.start()
    
    # 不断输出线程个数,当线程数threading.active_count()为1的时候,那么说明子线程全部运行完,还剩一个主线程
    while threading.active_count() != 1:
        # 你可以看到一共有23个,然后每过1秒减少5个,直到还有最后一个主线程
        print(threading.active_count())
    else:
        print('----all threads done---')
    

9. 队列如何使用?可以和线程之间产生什么互动?

队列是在一个 queue模块 当中,q = queue.Queue(maxsize=10)来实例化一个队列,q.put()来入队,q.get()来出队;可以和线程一起来建立一个 生产者消费者模型,生产者一边生产,生产完了入队,消费者检测,如果存在则直接输出消费掉。注意,若为空,则q.get()会一直在这里等待。

  • queue.Queue()
    import threading
    import time
    import queue
    
    # 生成一个队列对象,最大值为 10
    q = queue.Queue(maxsize=10)
    
    def Producer(name):
        count = 1
        while True:
            # 生产完进入队列
            q.put("骨头{}".format(count))
            print("生产了骨头",count)
            count += 1
            time.sleep(0.1)
    
    
    def Consumer(name):
        while True:
            # 若存在则直接输出
            print("[{}]取到[{}]并且吃了它...".format(name, q.get()))
            time.sleep(1)
    
    
    p = threading.Thread(target=Producer, args=("Alex",))
    c = threading.Thread(target=Consumer, args=("ChenRonghua",))
    x = threading.Thread(target=Consumer, args=("XiaoHengheng",))
    
    p.start()
    c.start()
    x.start()
    
本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值