Python线程

一、基础概念

1、并发vs并行

并发:指在一段时间内交替去执行任务
并行:指两个或多个时间在同一时刻执行


87f4c0ff7fbaa32a64fc2af2b35f061.png

2、进程vs线程

  • 进程:一个正在运行的程序或者软件就是一个进程,它是操作系统进行资源分配的基本单位
    一个进程默认有一个线程,进程里可以创建多个线程。程序启动默认会有一个主线程

  • 线程:线程是依附在进程里面的,没有进程就没有线程


    1538058d53c0edb3d1e3e1e7575fec2.png
  • 单线程示例:

import time

def play():
    print("hello,welcome to play")
    time.sleep(1)
    print("play end")
    
def sleep():
    print("hello,welcome to sleep")
    time.sleep(2)
    print("sleep end")
    
if __name__=='__main__':
    play()
    sleep()
image.png

二、多线程

1、线程的创建

class *threading.Thread(*group=None*, *target=None*, *name=None*, *args=()*, *kwargs={}*, ***, *daemon=None*)
group:线程组
target:执行目标的任务名
name:是线程名称。
args :以元组的形式给执行任务进行传参。 默认为 ()。
kwargs: 以字典的形式给执行任务进行传参。默认是 `{}`。

使用threading模块里面的Thread类创建出实例对象,然后通过start()方法真正的去产生一个新的线程

2、线程的常用方法

  • setDaemon() 设置守护线程时,主线程执行完了,子线程也结束了
  • join() 阻塞主线程 a.join() a为子线程,阻塞主线程,主线程会等待子线程a执行完了再执行下面
  • start() 启动子线程

3、单线程vs多线程实例

  • 单线程
import time
from threading import Thread

def play():
    print("hello,welcome to play")
    time.sleep(1)
    print("play end")
    
t1 = time.time()
if __name__=='__main__':
    
    for i in range(5):
        play()
        
t2 = time.time()
print("耗时时长:%f"%(t2-t1))
image.png
  • 多线程
import time
from threading import Thread

def play(name):
    print(f"hello,{name} to play")
    time.sleep(1)
    print("play end")
    
t1 = time.time()
if __name__=='__main__':
    
    for i in range(5):
        t = Thread(target=play,args=("张三+%d"%i,))
        t.start()
        
t2 = time.time()
print("耗时时长:%f"%(t2-t1))
image.png
  • Daemon的使用
import time
from threading import Thread

def play(name):
    print(f"hello,{name} to play")
    time.sleep(1)
    print("play end")
    
t1 = time.time()
if __name__=='__main__':
    
    for i in range(5):
        t = Thread(target=play,args=("张三+%d"%i,))
        t.setDaemon(True)
        t.start()
        
        print("我是主线程")
        
t2 = time.time()
print("耗时时长:%f"%(t2-t1))
image.png
  • join
import time
from threading import Thread

def play(name):
    print(f"hello,{name} to play")
    time.sleep(1)
    print("play end")
    
t1 = time.time()
if __name__=='__main__':
    
    for i in range(5):
        t = Thread(target=play,args=("张三+%d"%i,))
        t.setDaemon(True)
        t.start()
    t.join()
    print("我是主线程")
        
t2 = time.time()
print("耗时时长:%f"%(t2-t1))
image.png

三、线程的封装

**1、示例

import time
from threading import Thread

class MyThread(Thread):
    def run(self):
        print("comein")
        time.sleep(2)
        print("123")
        
if __name__=='__main__':
    print("comein 主线程")
    t = MyThread()
    t.start()
    print("主线程结束")
image.png

2、start() vs run()

  • start:start 方法是生命分到一个子线程的函数已经就绪,等待被CPU执行
  • run: run方法是执行到这个子线程时,自动调用的方法
import time
from threading import Thread
import threading

class MyThread(Thread):
    def run(self):
        print("当前线程执行的名称时:",threading.current_thread().name)
        
        
if __name__=='__main__':
    print("comein 主线程")
    t = MyThread()
    t.run()
    print("主线程结束")
image.png

image.png

**3、线程的无序

同样的代码,多次运行,结果不一样

import time
from threading import Thread
import threading

def task():
    time.sleep(2)
    print("当前执行的线程是:",threading.current_thread().name)
        
        
if __name__=='__main__':
    for i in range(5):
        t = Thread(target=task)
        t.start()
image.png

image.png

四、多线程的资源共享

import time
from threading import Thread

lst = []

def write_data():
    for i in range(10):
        lst.append(i)
        time.sleep(0.3)
    print(f"写入的数据是:{lst}")
        
def read_data():
    print("我读取到的数据是:",lst)
        
        
if __name__=='__main__':
    t = Thread(target=write_data)
    t1 = Thread(target=read_data)
    t.start()
    t1.start()
    print("主线程end")
print(lst)
image.png

这里资源共享的问题会造成:数据还没写完,就被读取完了,
可以用join来解决这个问题,等写完了后再执行后面的函数

import time
from threading import Thread

lst = []

def write_data():
    for i in range(10):
        lst.append(i)
        time.sleep(0.3)
    print(f"写入的数据是:{lst}")
        
def read_data():
    print("我读取到的数据是:",lst)
        
        
if __name__=='__main__':
    t = Thread(target=write_data)
    t1 = Thread(target=read_data)
    t.start()
    t.join()
    t1.start()
    print("主线程end")
print(lst)
image.png

五、多线程的资源竞争

**1、示例:

from threading import Thread

a = 0
b = 1000000

def sum1():
    global a
    for i in range(b):
        a += 1
    print("第一次计算a:",a)
    
#sum1()

def sum2():
    global a
    for i in range(b):
        a += 1
    print("第二次计算a:",a)
    
#sum2()

if __name__ == '__main__':
    t1 = Thread(target=sum1)
    t2 = Thread(target=sum2)
    t1.start()
    t2.start()
image.png

2、资源竞争的解决方案

  • 线程等待 join (同步):

同步:先后顺序执行,例如:你先说完,我再说。


image.png
  • 互斥锁:

能够保证多个线程访问共享数据不会出现数据错误问题。对共享书进行锁定,保证同一时刻只有一个线程操作。
1)互斥锁的使用:
加锁acquire()
释放锁release()
acquire和release总是成对出现
2)示例:

from threading import Thread,Lock

a = 0
b = 1000000

lock = Lock()

def sum1():
    lock.acquire()
    global a
    for i in range(b):
        a += 1
    print("第一次计算a:",a)
    lock.release()
    
#sum1()

def sum2():
    lock.acquire()
    global a
    for i in range(b):
        a += 1
    print("第二次计算a:",a)
    lock.release()
    
#sum2()

if __name__ == '__main__':
    t1 = Thread(target=sum1)
    t2 = Thread(target=sum2)
    t1.start()
    t2.start()
image.png
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容