专栏首页AutoML(自动机器学习)python多线程学习笔记(超详细)

python多线程学习笔记(超详细)

python

threading

多线程

一. Threading简介

首先看下面的没有用Threading的程序

import threading,time 
 
def fun(): 
    s = 0 
 for i in range(30): 
        s += i 
        time.sleep(0.1) 
    print(s) 
 
if __name__ == '__main__': 
    t = time.time() 
    fun() 
    fun() 
    print(time.time()-t) 
 
>>>  
435 
435 
6.023701906204224 
[Finished in 6.6s] 

如果使用线程会有什么样的效果呢

import threading,time 
 
def fun(): 
    s = 0 
 for i in range(30): 
        s += i 
        time.sleep(0.1) 
    print(s) 
 
if __name__ == '__main__': 
 # 创建了一个线程列表,包含2个线程 
    ths = [threading.Thread(target=fun) for i in range(2)] 
 for th in ths: 
        th.start() 
    t = time.time() 
 for th in ths: 
        th.join() 
    print(time.time()-t) 
 
 
>>>  
435 
435 
3.116874933242798 
[Finished in 3.7s] 

这说明两个线程几乎是同时进行的

二. Threading的应用进阶

  1. join(timeout)用来实现线程等待。 被调用join()方法的线程会一直阻塞调用者的线程, 直到自己结束(正常结束,或引发未处理异常), 或超出timeout的时间。
import threading,time 
 
class MyThread(threading.Thread): 
 
 def run(self): 
 for i in range(30): 
            print('threading:',i) 
            time.sleep(0.1) 
 
if __name__ == '__main__': 
    t = MyThread() 
    t.start() 
    t.join(1) 
 for i in range(10): 
        print('Main:',i) 
        time.sleep(0.1) 
 
>>>  
threading: 0 
threading: 1 
threading: 2 
主线程等待t这个线程0.1秒后也开始运行 
Main: 0 
threading: 3 
Main: 1 
threading: 4 
Main: 2 
threading: 5 
Main: 3 
threading: 6 
Main: 4 
threading: 7 
Main: 5 
threading: 8 
Main: 6 
threading: 9 
Main: 7 
Main: 8 
Main: 9 
[Finished in 2.0s] 

注意每次运行的结果都不太一样

2)daemon属性 被设定为后台运行的线程,会在主程序退出时主动自杀。 设置为后台运行线程的方法是:设置线程的daemon属性为True

import threading,time 
 
def dmn(): 
    print('dmn start...') 
    time.sleep(2) 
    print('dmn end.') 
 
def ndmn(): 
    print('ndmn start...') 
    time.sleep(1) 
    print('ndmn end.') 
 
d = threading.Thread(target=dmn) 
d.daemon = True 
n = threading.Thread(target=ndmn) 
print('start...') 
d.start() 
n.start() 
print('end.') 
 
>>> 
start... 
dmn start... 
ndmn start... 
end. 
ndmn end. 
[Finished in 1.3s] 

由上面打印的结果我们可以看到dmn线程设置为后台线程后,它的 print('dmn end.') 语句并不没有执行,这是因为后台线程在主线程结束后会自杀,所以主线程执行完后,dmn线程没能说出自己的“遗言”。 作为对比,我将daemon设为False,结果如下

... 
 
d = threading.Thread(target=dmn)  
d.daemon = False 
... 
 
>>> 
start... 
dmn start... 
ndmn start... 
end. 
ndmn end. 
dmn end. 
[Finished in 2.5s] 
线程同步
1 )指令锁 threading.Lock

acquire尝试获得锁定,进入阻塞状态。 acquire(blocking=True, timeout=-1))

release释放获得锁定(资源使用完后) release()

import threading,time,random 
 
share = 4 
lock = threading.Lock() #初始化指令锁 
 
class MyThread(threading.Thread): 
 def __init__(self,i): 
        super().__init__() 
        self.i = i 
 
 def run(self): 
 global share 
 for d in range(2): 
            lock.acquire() 
            print(share) 
            share += self.i 
            time.sleep(random.random()) 
            print('+',self.i,'=',share) 
            lock.release() 
 
if __name__ == '__main__': 
    t = MyThread(2) 
    tt = MyThread(6) 
    t.start() 
    tt.start() 
 
>>> 
4 
+ 2 = 6 
6 
+ 6 = 12 
12 
+ 2 = 14 
14 
+ 6 = 20 
[Finished in 2.9s] 

为了更好的感受指令锁的作用,将acquire和release去掉后结果如下

... 
def run(self): 
 global share  
 for d in range(2):  
 # lock.acquire()  
            print(share)  
            share += self.i  
            time.sleep(random.random())  
            print('+',self.i,'=',share)  
 # lock.release()  
... 
 
>>> 
4 
6 
+ 6 = 12 
12 
+ 2 = 18 
18 
+ 6 = 20 
+ 2 = 20 
[Finished in 2.2s] 

比较后可以知道,加了指令锁后可以清楚地知道对共享资源share操作的具体情况

2 )条件变量threading.Condition 属性

  • 实例化时,可指定锁。
  • acquire()
  • release()
  • wait(timeout=None) 释放锁,进入等待阻塞, 直到唤醒或超时。
  • notify(n=1) 唤醒等待该条件变量的线程。默认1个。
  • notify_all() 唤醒等待该条件变量的所有线程。

实现严格的依照次序操作的线程之间的通信。 典型的实例:生产者/消费者(只有生产后,才能消费)。 线程之间可以互相通知,以达到默契的配合。 条件变量可以使用默认的锁或用户创建的锁来工作。

话不多说看代码

import threading,time 
 
share = 0 
 
share_cond = threading.Condition() 
 
# 生产者 
class ProThread(threading.Thread): 
 def __init__(self): 
        super().__init__() 
        self.name = 'Produce' 
 
 def run(self): 
 global share 
 if share_cond.acquire(): 
 while True: 
 if not share:   # 若没东西了,即开始生产 
                    share += 1 
                    print(self.name,share) 
                    share_cond.notify() #唤醒消费者?这个是我自己的理解  
                share_cond.wait() 
                time.sleep(1) 
 
# 消费者 
class CustomThread(threading.Thread): 
 def __init__(self): 
        super().__init__() 
        self.name = 'Custom' 
 
 def run(self): 
 global share 
 if share_cond.acquire(): 
 while True: 
 if share: 
                    share -= 1 # 若有东西就买买买 
                    print(self.name,share) 
                    share_cond.notify() #唤醒生产者,同上,仅是个人理解,如有错请告知,谢谢 
                share_cond.wait() 
                time.sleep(1) 
 
if __name__ == '__main__': 
    t  = ProThread() 
    tt = CustomThread() 
    t.start() 
    tt.start() 
 
>>> 
Produce 1 
Custom 0 
Produce 1 
Custom 0 
Produce 1 
Custom 0 
... 
... 
... 

上面的结果会一直重复执行下去

3 ) 信号量threading.Semaphore

属性

  • 实例化时,指定使用量。
  • 其内置计数器,锁定时+1, 释放时-1,计数器为0则阻塞。
  • acquire(blocking=True,timeout=None)
  • release()释放锁。
import threading,time 
 
sema = threading.Semaphore(2) 
 
class MyThread(threading.Thread): 
 def __init__(self,name): 
        super().__init__() 
        self.name = name 
 
 def run(self): 
 if sema.acquire(): 
            print(self.name,'Had got resource.') 
            time.sleep(1) 
        sema.release() 
        print(self.name,'Had released resource.') 
 
if __name__ == '__main__': 
    ths = [MyThread(str(i)+'Sema') for i in range(5)] 
 for th in ths: 
        th.start() 
 
>>> 
0Sema Had got resource. 
1Sema Had got resource. 
2Sema Had got resource. 
1Sema Had released resource. 
3Sema Had got resource. 
0Sema Had released resource. 
3Sema Had released resource. 
4Sema Had got resource. 
2Sema Had released resource. 
4Sema Had released resource. 
[Finished in 3.6s] 

4 ) 线程通信threading.Event

  • 其管理一个内部标志.实现一个线程,唤醒其它线程。
  • set() 设置内部标志为True
  • clear() 设置内部标志为False
  • wait(timeout) 阻塞线程,到内部标志为True。
import threading,time 
 
event = threading.Event() 
 
class MyThreadWait(threading.Thread): 
 def run(self): 
        self.name = 'Wait Thread' 
        print(self.name,"Wait...") 
        event.wait() 
        print(self.name,"Start...") 
        event.clear() 
 
class MyThreadMain(threading.Thread): 
 def run(self): 
        time.sleep(3) 
        print('Main thread set event flag!') 
        event.set() 
 
if __name__ == '__main__': 
    thw = MyThreadWait() 
    thm = MyThreadMain() 
    thw.start() 
    thm.start() 
 
>>> 
Wait Thread Wait... 
Main thread set event flag! 
Wait Thread Start... 
[Finished in 3.6s] 

好了,大概就是这些了,其他的以后再补充,另外感谢麦子学院提供的免费课程~~~真心不是打广告

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Pytorch Sampler详解

    其原理是首先在初始化的时候拿到数据集data_source,之后在__iter__方法中首先得到一个和data_source一样长度的range可迭代器。每次只...

    marsggbo
  • pyqt4实现tab界面切换

    de ># -*- coding: utf-8 -*- from PyQt4.QtGui import * from PyQt4.QtCore import...

    marsggbo
  • Python print输出重定向到文件和屏幕,超简单

    marsggbo
  • python3多线程趣味详解

    python3的多线程很多人无法理解是怎么运行的,因此本文从程序猿的日常生活出发,写了一个由浅入深的多线程教程,这样子大家就不会觉得陌生了,多线程真的很简单很简...

    机器学习和大数据挖掘
  • Python类super()及私有属性原理解析

    砸漏
  • python_time和datetime

    struct_time元组共有9个元素,返回struct_time的函数主要有gmtime(),localtime(),strptime()。

    py3study
  • 深入理解异步事件机制

    显然易见的是,同步的概念随着我们学习第一个输出Hello World的程序,就已经深入人心。

    py3study
  • python--time模块

    time.localtime([secs])  默认将当前时间戳转成当前时区的struct_time

    py3study
  • 零基础入门深度学习 | 第三章:神经网络和反向传播算法

    无论即将到来的是大数据时代还是人工智能时代,亦或是传统行业使用人工智能在云上处理大数据的时代,作为一个有理想有追求的程序员,不懂深度学习这个超热的技术,会不会感...

    用户1332428
  • python编写的串口程序

    最近导师给了个GSM模块,需要通过RS232串口发送AT指令来对模块进行控制,于是看了看python的GUI设计和串口部分的资料,自己编写了一个串口发送的小程序...

    py3study

扫码关注云+社区

领取腾讯云代金券