美文网首页
(6) python 多线程

(6) python 多线程

作者: 小黄不头秃 | 来源:发表于2022-10-21 01:19 被阅读0次

(一)多线程编程

随着电脑硬件的发展,我们的电脑由最开始的单核CPU到现在的多核CPU,电脑的性能越来越强,我们希望我们的代码尽可能的越快越好,所以我们有时候需要开辟多个线程,让代码并行。

关于线程进程的一些基础知识,可以看我以前的笔记:
【1】https://www.jianshu.com/p/9992a3123870
其他更加详细的帖子:
【2】https://zhuanlan.zhihu.com/p/477826233

  • 线程(Thread)是操作系统中能够进行运算的最小单位,他能够被包含在进程之中,是进程的实际运作单位。

  • 进程拥有独立的系统资源,该进程下的所有线程共享进程所拥有的计算机资源。线程之间可以并发执行。

多线程的使用分为两步:

  1. 创建线程
  2. 开启线程
  3. 其他操作

线程同步:需要等待使用资源,效率低但安全性高,需要注意死锁问题
线程异步:线程之间互不干扰各执行各的,执行效率高,但是数据容易脏。

(1) threading 模块提供的其他方法:

Python多线程的默认情况(设置线程setDaemon(False)),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。p.join只能join住start开启的进程,而不能join住run开启的进程
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。
  • setDaemon():当setDaemon为true时,主线程结束后,无论子线程1,2是否运行完成,都结束不再往下继续运行。
(2)关于setdaemon和join之间的区别
# 默认情况
import threading
import time
from time import sleep

def fun(a):
    for _ in range (10):
        print(threading.currentThread())
        sleep(a)

# 创建一个线程
thread1 = threading.Thread(target=fun,args=(1,),name="t1") # 10s
thread2 = threading.Thread(target=fun,args=(0.5,),name="t2") # 5s

# 运行线程
thread1.start()
thread2.start()

print("主线程结束",time.strftime("%H:%M:%S"))

# <Thread(t1, started 17164)>
# <Thread(t2, started 15732)>
# 主线程结束 03:14:32        
# <Thread(t2, started 15732)>
# <Thread(t1, started 17164)>
# <Thread(t2, started 15732)>
# <Thread(t2, started 15732)>
# <Thread(t1, started 17164)>
# <Thread(t2, started 15732)>
# <Thread(t2, started 15732)>
# <Thread(t1, started 17164)>
# <Thread(t2, started 15732)>
# <Thread(t2, started 15732)>
# <Thread(t1, started 17164)>
# <Thread(t2, started 15732)>
# <Thread(t2, started 15732)>
# <Thread(t1, started 17164)>
# <Thread(t1, started 17164)>
# <Thread(t1, started 17164)>
# <Thread(t1, started 17164)>
# <Thread(t1, started 17164)>

# 主线程不干扰子线程,各运行各的。

# 开启守卫线程
import threading
import time
from time import sleep

def fun(a):
    for _ in range (10):
        print(threading.currentThread())
        sleep(a)

# 创建一个线程
thread1 = threading.Thread(target=fun,args=(1,),name="t1") # 10s
thread2 = threading.Thread(target=fun,args=(0.5,),name="t2") # 5s

# 运行线程
thread1.setDaemon(True)
thread1.start()
thread2.setDaemon(True)
thread2.start()

print("主线程结束",time.strftime("%H:%M:%S"))

# <Thread(t1, started daemon 15056)>
# <Thread(t2, started daemon 16176)>
# 主线程结束 03:10:35

# 主线程一结束,立刻杀死所有子线程

# 设置join,不设置守护线程
import threading
import time
from time import sleep

def fun(a):
    for i in range (10):
        print(threading.currentThread())
        sleep(a)

# 创建一个线程
thread1 = threading.Thread(target=fun,args=(1,),name="t1") # 10s
thread2 = threading.Thread(target=fun,args=(0.5,),name="t2") # 5s

# 运行线程
thread1.start()
thread2.start()
print("等待线程1:",time.strftime("%H:%M:%S"))
thread1.join() # 只要有一个join,主线程就被堵住了,但是不会影响子线程的运行,直到所有join的子线程执行完。
print("等待线程2",time.strftime("%H:%M:%S"))
thread2.join()
print("前面两个子线程运行结束!",time.strftime("%H:%M:%S"))

# <Thread(t1, started 16500)>
# <Thread(t2, started 15664)>
# 等待线程1: 03:01:13        
# <Thread(t2, started 15664)>
# <Thread(t1, started 16500)>
# <Thread(t2, started 15664)>
# <Thread(t2, started 15664)>
# <Thread(t1, started 16500)>
# <Thread(t2, started 15664)>
# <Thread(t2, started 15664)>
# <Thread(t1, started 16500)>
# <Thread(t2, started 15664)>
# <Thread(t2, started 15664)>
# <Thread(t1, started 16500)>
# <Thread(t2, started 15664)>
# <Thread(t2, started 15664)>
# <Thread(t1, started 16500)>
# <Thread(t1, started 16500)>
# <Thread(t1, started 16500)>
# <Thread(t1, started 16500)>
# <Thread(t1, started 16500)>
# 等待线程2 03:01:23
# 前面两个子线程运行结束! 03:01:23

# 主线程一遇到join就会被卡住,等待两个线程运行结束,再接着执行主程序,
# 如果主程序执行完还有未执行完的子线程,不会杀死该子线程
(3)自定义线程类
from time import sleep
from threading import Thread
class MyThread(Thread):
    def __init__(self,name):
        super(MyThread,self).__init__()
        self.name = name

    def run(self):
        for _ in range(5):
            print(self.name,"is running!")
            sleep(1)

# 创建线程
thread1 = MyThread("t1")
thread2 = MyThread("t2")

# 开启线程
thread1.start()
thread2.start()

print("主线程结束!")

# t1 is running!
# t2 is running!
# 主线程结束!
# t2 is running!
# t1 is running!
# t2 is running!
# t1 is running!
# t2 is running!
# t1 is running!
# t1 is running!
# t2 is running!
(4)lock

在线程中,有一些资源是共享的,例如全局变量。多个线程之间可能会出现同时使用资源的时候。可以给数据加把锁,来防止脏读,等。比较经典的就是生产者,消费者模型,可以去了解一下。

# 不加锁的情况
import threading
import time
from time import sleep

shared_data1 = []
shared_data2 = []
shared_data3 = []


def fun():
    """累加器, 循环1000次"""
    global shared_data1
    global shared_data2
    global shared_data3
    for _ in range(1000):
        # 模拟读取数据
        data1 = shared_data1.copy()
        data2 = shared_data2.copy()
        data3 = shared_data3.copy()
        # 模拟修改数据
        data1.extend(["a"]*10)
        data2.extend(["a"]*10)
        data3.extend(["a"]*10)
        # 模拟写入数据
        shared_data1 =  data1
        shared_data2 =  data2
        shared_data3 =  data3

# 创建线程
thread1 =threading.Thread(target=fun,args=(),name="t1")
thread2 =threading.Thread(target=fun,args=(),name="t2")

# 开启线程
thread1.start()
thread2.start()

# 阻塞主进程
thread1.join()
thread2.join()

print(len(shared_data1) == len(shared_data2) == len(shared_data3))# 理论上应当为True结果为False
print(len(shared_data1),len(shared_data2),len(shared_data3))# 理论上应当为20000,结果为17110 17720 17250
# 加上锁以后
import threading
import time
from time import sleep

shared_data1 = []
shared_data2 = []
shared_data3 = []
lock = threading.Lock()

def fun():
    """累加器, 循环10000次"""
    global shared_data1
    global shared_data2
    global shared_data3
    global lock
    for _ in range(10000):
        lock.acquire()
        # 模拟读取数据
        data1 = shared_data1.copy()
        data2 = shared_data2.copy()
        data3 = shared_data3.copy()
        # 模拟修改数据
        data1.extend(["a"]*10)
        data2.extend(["a"]*10)
        data3.extend(["a"]*10)
        # 模拟写入数据
        shared_data1 =  data1
        shared_data2 =  data2
        shared_data3 =  data3
        lock.release()

# 创建线程
thread1 =threading.Thread(target=fun,args=(),name="t1")
thread2 =threading.Thread(target=fun,args=(),name="t2")

# 开启线程
thread1.start()
thread2.start()

# 阻塞主进程
thread1.join()
thread2.join()

print(len(shared_data1) == len(shared_data2) == len(shared_data3))# 理论上应当为True,结果为True
print(len(shared_data1),len(shared_data2),len(shared_data3))# 理论上应当为200000,结果为200000 200000 200000

相关文章

  • python与shell多线程区别

    分别用python和shell写一个多线程脚本执行1~6.sh脚本(多线程数设置为 2),6个脚本执行耗时不一样,...

  • (6) python 多线程

    (一)多线程编程 随着电脑硬件的发展,我们的电脑由最开始的单核CPU到现在的多核CPU,电脑的性能越来越强,我们希...

  • GIL

    谈谈python的GIL、多线程、多进程 最近在看 Python 的多线程,经常我们会听到老手说:“python下...

  • Python多线程编程——多线程编程中的加锁机制

    如果大家对Python中的多线程编程不是很了解,推荐大家阅读之前的两篇文章:Python多线程编程——多线程基础介...

  • 5-线程(补充)

    Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了...

  • Python_提高

    GIL全局解释器锁 描述Python GIL的概念, 以及它对python多线程的影响?编写⼀个 多线程抓取⽹⻚的...

  • Python程序员都知道的入门知识の八

    目录【Python程序员都知道的入门知识】 1. 多线程threading、Queue Python的多线程由th...

  • Python多线程实现生产者消费者

    1. Python多线程介绍 Python提供了两个有关多线程的标准库,thread和threading。thre...

  • 多线程

    Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了...

  • Python多线程(上)

    前言 说起Python的多线程,很多人都嗤之以鼻,说Python的多线程是假的多线程,没有用,或者说不好用,那本次...

网友评论

      本文标题:(6) python 多线程

      本文链接:https://www.haomeiwen.com/subject/jnhyartx.html