python3 多线程编程

简介:

0.什么是线程

  1. 多线程模块

  2. 创建线程的方法

  3. join()方法

4.isAlive()方法

  1. name属性和daemon属性

6.线程的同步---锁

7.线程的同步---Event对象

8.线程的同步---Condition条件变量

0.什么是线程

线程是CPU分配资源的基本单位。但一个程序开始运行,这个程序就变成了一个进程,而一个进程相当于一个或者多个线程。当没有多线程编程时,一个进程也是一个主线程,但有多线程编程时,一个进程包含多个线程,包括主线程。使用线程可以实现程序的并发。

  1. 多线程模块

python3对多线程支持的是 threading 模块,应用这个模块可以创建多线程程序,并且在多线程间进行同步和通信。在python3 中,可以通过两种方法来创建线程:

第一:通过 threading.Thread 直接在线程中运行函数;第二:通过继承 threading.Thread 类来创建线程

  1. 创建线程的方法

1.用 thread.Thread 直接在线程中运行函数

[python] view plain copy

import threading  

def threadfun(x,y):         #线程任务函数 threadfun()  
    for i in range(x,y):  
        print(i)  

ta = threading.Thread(target=threadfun,args=(1,6))      #创建一个线程ta,执行 threadfun()  
tb = threading.Thread(target=threadfun,args=(10,15))    #创建一个线程tb,执行threadfun()  
ta.start()          #调用start(),运行线程  
tb.start()          #调用start(),运行线程  
'''''打印:1 2 3 4 5 10 11 12 13 14'''  

2.通过继承 thread.Thread 类 来创建线程

这种方法只需要重载 threading.Thread 类的 run 方法,然后调用 start()开启线程就可以了

[python] view plain copy

import threading  

class mythread(threading.Thread):  
    def run(self):  
        for i in range(1,5):  
            print(i)  

ma = mythread();  
mb = mythread();  
ma.start()  
mb.start()  
  1. join()方法

join()作用是 调用 join() 的线程 阻塞直到 某一线程结束才继续执行

[python] view plain copy

import threading  
import time  
class mythread(threading.Thread):  
    def run(self):  
        self.i = 1  
        print('%d'%(self.i))  
        self.i = self.i+1  
        time.sleep(1)           #睡眠一秒  
        print('%d'%(self.i))  
        time.sleep(1)  

if __name__ == '__main__':  
    ta = mythread()     #实例化线程  
    ta.start()          #开启ta线程  
    ta.join()           #主线程等待 ta线程结束才继续执行  
    print('main thread over')  

4.isAlive()方法

这个方法用于判断线程是否运行。

1.当线程未调用 start()来开启时,isAlive()会返回False

2.但线程已经执行后并结束时,isAlive()也会返回False

[python] view plain copy

import threading  
import time  
class mythread(threading.Thread):  
    def run(self):  
       time.sleep(2)  

if __name__ == '__main__':  
    ta = mythread()     #实例化线程  
    print(ta.isAlive())   #打印False,因为未执行 start()来使ta线程运行  
    ta.start()  
    print(ta.isAlive())   #打印Ture,因为ta线程运行了  
    time.sleep(3)  
    print(ta.isAlive())   #打印False,因为ta线程已经结束了  
  1. name属性和daemon属性

1.name属性表示线程的线程名 默认是 Thread-x x是序号,由1开始,第一个创建的线程名字就是 Thread-1

[python] view plain copy

import threading  
import time  
class mythread(threading.Thread):  
    def run(self):  
        pass  

if __name__ == '__main__':  
    ta = mythread()     #实例化线程  
    ta.name = 'thread-ta'  
    tb = mythread()  
    tb.start()  
    ta.start()  

    print(ta.name)  #打印 thread-ta  
    print(tb.name)  #打印 Thread-2  

2.daemon属性用来设置线程是否随主线程退出而退出

当 daemon = False 时,线程不会随主线程退出而退出(默认时,就是 daemon = False)

当 daemon = True 时,当主线程结束,其他子线程就会被强制结束

[python] view plain copy

import threading  
import time  
class mythread(threading.Thread):  
    def run(self):  
        time.sleep(2)  
        print('my thread over')  

def main():  
    ta = mythread()  
    ta.daemon = True  
    ta.start()  
    print('main thread over')  

if __name__ == '__main__':  
    main()  
#打印结果 :main thread over   然后马上结束程序  

6.线程的同步---锁
当一个进程拥有多个线程之后,如果他们各做各的任务互没有关系还行,但既然属于同一个进程,他们之间总是具有一定关系的。比如多个线程都要对某个数据进行修改,则可能会出现不可预料的结果。为保证操作正确,就需要引入锁来进行线程间的同步。

python3 中的 threading 模块提供了 RLock锁(可重入锁)。对于某一时间只能让一个线程操作的语句放到 RLock的acquire 方法 和 release方法之间。即 acquire()方法相当于给RLock 锁 上锁,而 release() 相当于解锁。

[python] view plain copy

import threading  
import time  

class mythread(threading.Thread):  
    def run(self):  
        global x            #声明一个全局变量  
        lock.acquire()      #上锁,acquire()和release()之间的语句一次只能有一个线程进入,其余线程在acquire()处等待  
        x += 10  
        print('%s:%d'%(self.name,x))  
        lock.release()      #解锁  

x = 0  
lock = threading.RLock()    #创建 可重入锁  
def main():  
    l = []  
    for i in range(5):  
        l.append(mythread())    #创建 5 个线程,并把他们放到一个列表中  
    for i in l:  
        i.start()               #开启列表中的所有线程  

if __name__ =='__main__':  
    main()  

打印结果:

Thread-1:10
Thread-2:20
Thread-3:30
Thread-4:40
Thread-5:50

7.线程的同步---Event对象
Event对象存在于 threading 模块中。Event 实例管理着 一个内部标志,通过 set() 方法来将该标志设置成 True,使用 clear() 方法将该标志重置成 False

wait() 方法会使当前线程阻塞直到标志被设置成 True,wait()可以选择给他一个参数,代表时间,代表阻塞多长时间,若不设置就是阻塞直到标志被设置为True

isSet()方法 :能判断标志位是否被设置为True

[python] view plain copy

import threading  
import time  

class Mon(threading.Thread):  
    def run(self):  
        Dinner.clear()  
        print('Cooking dinner')  
        time.sleep(3)  
        Dinner.set()    #标志设置为True  
        print(self.name,':dinner is OK!')  

class Son(threading.Thread):  
    def run(self):  
        while True:  
            if Dinner.isSet():  #判断标志位是否被设置为True  
                break  
            else:  
                print('dinner isnot ready!')  
                Dinner.wait(1)  

        print(self.name,':Eating Dinner')  

def main():  
    mon = Mon()  
    son = Son()  
    mon.name = 'Mon'  
    son.name = 'Son'  
    mon.start()  
    son.start()  

if __name__ == '__main__':  
    Dinner = threading.Event()  
    main()  

''''' 
Cooking dinner 
dinner isnot ready! 
dinner isnot ready! 
dinner isnot ready! 
Mon :dinner is OK! 
Son :Eating Dinner 
'''  

8.线程的同步---Condition条件变量

条件变量表示当线程满足某一个 条件才被唤醒,否则一直阻塞

对比 只用锁不用条件变量 的好处就是:只用锁的话,如果一个线程在上锁后,解锁前,因为某一条件一直阻塞着,那么锁就一直解不开,那么其他线程也就因为一直获取不了锁而跟着阻塞着,这样效率就不好,浪费了很多时间。对于这种情况,锁+条件变量可以让该线程先 解锁,然后阻塞着,等待条件满足了,再重新唤醒并获取锁(上锁)。这样就不会因为一个线程阻塞着而影响其他线程也跟着阻塞了。

Condition 提供的方法:

acquire() 和 release() 表示上锁和解锁,和 单纯的锁机制一样。

wait() 解开锁,阻塞,直到其他线程调用了notify()或者notifyAll才被唤醒,注意,这里的wait()跟上面Event提到的wait()不是同一样东西

notify() 发出资源可用的信号,唤醒任意一条因 wait()阻塞的进程

notifyAll() 发出资源可用信号,唤醒所有因wait()阻塞的进程

下面给出一个例子,一家蛋糕店:只会做一个蛋糕,卖出后才会再做一个。绝对不会做积累到2个蛋糕。

[python] view plain copy

import threading  
import time  

class Server(threading.Thread):  
    def run(self):  
        global x  
        while True:  
            con.acquire()  
            while x>0:  
                con.wait()  
            x += 1  
            time.sleep(1)  
            print(self.name,':I make %d cake!'%(x))  
            con.notifyAll()  
            con.release()  

class Client(threading.Thread):  
    def run(self):  
        global x  
        con.acquire()  
        while x == 0:  
            con.wait()  
        x-=1  
        print(self.name,'I bought a cake! the rest is %d cake'%(x))  
        con.notifyAll()  
        con.release()  

def main():  
    ser = Server()  
    ser.name = 'Cake Server'  
    client = []  
    for i in range(3):  
        client.append(Client())  
    ser.start()  
    for c in client:  
        c.start()  

if __name__ =='__main__':  
    x = 0  
    con = threading.Condition()  
    main()  
''''' 
打印结果: 
Cake Server :I make 1 cake! 
Thread-3 I bought a cake! the rest is 0 cake 
Cake Server :I make 1 cake! 
Thread-4 I bought a cake! the rest is 0 cake 
Cake Server :I make 1 cake! 
Thread-2 I bought a cake! the rest is 0 cake 

Cake Server :I make 1 cake!


''' 本文转自 Forande 51CTO博客,原文链接:http://blog.51cto.com/853056088/2047651
相关文章
|
10天前
|
存储 数据挖掘 开发者
Python编程入门:从零到英雄
在这篇文章中,我们将一起踏上Python编程的奇幻之旅。无论你是编程新手,还是希望拓展技能的开发者,本教程都将为你提供一条清晰的道路,引导你从基础语法走向实际应用。通过精心设计的代码示例和练习,你将学会如何用Python解决实际问题,并准备好迎接更复杂的编程挑战。让我们一起探索这个强大的语言,开启你的编程生涯吧!
|
4天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
3天前
|
Python
Python编程入门:从零开始的代码旅程
本文是一篇针对Python编程初学者的入门指南,将介绍Python的基本语法、数据类型、控制结构以及函数等概念。文章旨在帮助读者快速掌握Python编程的基础知识,并能够编写简单的Python程序。通过本文的学习,读者将能够理解Python代码的基本结构和逻辑,为进一步深入学习打下坚实的基础。
|
7天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
6天前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
10天前
|
存储 人工智能 数据挖掘
Python编程入门:打造你的第一个程序
本文旨在为初学者提供Python编程的初步指导,通过介绍Python语言的基础概念、开发环境的搭建以及一个简单的代码示例,帮助读者快速入门。文章将引导你理解编程思维,学会如何编写、运行和调试Python代码,从而开启编程之旅。
34 2
|
11天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
11天前
|
存储 Python
Python编程入门:理解基础语法与编写简单程序
本文旨在为初学者提供一个关于如何开始使用Python编程语言的指南。我们将从安装Python环境开始,逐步介绍变量、数据类型、控制结构、函数和模块等基本概念。通过实例演示和练习,读者将学会如何编写简单的Python程序,并了解如何解决常见的编程问题。文章最后将提供一些资源,以供进一步学习和实践。
24 1
|
12天前
|
机器学习/深度学习 存储 数据挖掘
Python 编程入门:理解变量、数据类型和基本运算
【10月更文挑战第43天】在编程的海洋中,Python是一艘易于驾驭的小船。本文将带你启航,探索Python编程的基础:变量的声明与使用、丰富的数据类型以及如何通过基本运算符来操作它们。我们将从浅显易懂的例子出发,逐步深入到代码示例,确保即使是零基础的读者也能跟上步伐。准备好了吗?让我们开始吧!
23 0
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
48 1
C++ 多线程之初识多线程