python多线程

简介: 在介绍Python中的线程之前,先明确一个问题,Python中的多线程是假的多线程! 为什么这么说,我们先明确一个概念,全局解释器锁(GIL)什么是GILPython代码的执行由Python虚拟机(解释器)来控制,同时只有一个线程在执行。

在介绍Python中的线程之前,先明确一个问题,Python中的多线程是假的多线程!
为什么这么说,我们先明确一个概念,全局解释器锁(GIL)

什么是GIL

Python代码的执行由Python虚拟机(解释器)来控制,同时只有一个线程在执行。对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个线程在运行。

为什么要GIL

为了线程间数据的一致性和状态同步的完整性,(例如:线程2需要线程1执行完成的结果,然而线程2又比线程1执行时间短,线程2执行完成,线程1仍然还在执行,这就是数据的同步性)

GIL的影响

只有一个线程在运行,无法使用多核。

  • 在多线程环境中,Python虚拟机按照以下方式执行。

    1.设置GIL。
    2.切换到一个线程去执行。
    3.运行。
    4.把线程设置为睡眠状态。
    5.解锁GIL。
    6.再次重复以上步骤。
    比方我有一个4核的CPU,那么这样一来,在单位时间内每个核只能跑一个线程,然后时间片轮转切换。
    但是Python不一样,它不管你有几个核,单位时间多个核只能跑一个线程,然后时间片轮转。
    执行一段时间后让出,多线程在Python中只能交替执,10核也只能用到1个核
    例如:

from threading import Thread
def loop():
    while True:
        print("亲爱的,我错了,我能吃饭了吗?")

if __name__ == '__main__':

    for i in range(3):
        t = Thread(target=loop)
        t.start()

    while True:
        pass

而如果我们变成进程呢?cpu –100%

from multiprocessing import Process
def loop():
    while True:
        print("亲爱的,我错了,我能吃饭了吗?")

if __name__ == '__main__':

    for i in range(3):
        t = Process(target=loop)
        t.start()

    while True:
        pass

多线程怎么使用多核

  • 1、重写python编译器(官方cpython)如使用:PyPy解释器
  • 2、调用C语言的链接库

cpu密集型(计算密集型)、I/O密集型

  • 计算密集型任务由于主要消耗CPU资源,代码运行效率至关重要,C语言编写
  • IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成99%的时间花费在IO上,脚本语言是首选,C语言最差。

2、创建多线程

def doSth(arg):
    # 拿到当前线程的名称和线程号id
    threadName = threading.current_thread().getName()
    tid = threading.current_thread().ident
    for i in range(5):
        print("%s *%d @%s,tid=%d" % (arg, i, threadName, tid))
        time.sleep(2)

1、使用_thread.start_new_thread开辟子线程

def simpleThread():
    # 创建子线程,执行doSth
    # 用这种方式创建的线程为【守护线程】(主线程死去“护卫”也随“主公”而去)
    _thread.start_new_thread(doSth, ("拍森",))

    mainThreadName = threading.current_thread().getName()
    print(threading.current_thread())
    # 5秒的时间以内,能看到主线程和子线程在并发打印
    for i in range(5):
        print("劳资是主线程@%s" % (mainThreadName))
        time.sleep(1)

    # 阻塞主线程,以使【守护线程】能够执行完毕
    while True:
        pass

2、 通过创建threading.Thread对象实现子线程

def threadingThread():
    # 默认不是【守护线程】
    t = threading.Thread(target=doSth, args=("大王派我来巡山",)) # args=(,) 必须是元组
    # t.setDaemon(True)  # 设置为守护线程
    t.start()  # 启动线程,调用run()方法
    t.join()  # 等待

3、通过继承threading.Thread类,进而创建对象实现子线程

class MyThread(threading.Thread):
    def __init__(self, name, task, subtask):
        super().__init__()

        self.name = name  # 覆盖了父类的name
        self.task = task  # MyThread自己的属性
        self.subtask = subtask

    # 覆写父类的run方法,
    # run方法以内为【要跑在子线程内的业务逻辑】(thread.start()会触发的业务逻辑)
    def run(self):
        for i in range(5):
            print("[%s]并[%s] *%d @%s" % (self.task, self.subtask, i, threading.current_thread().getName()))
            time.sleep(2)


def classThread():
    mt = MyThread("小分队I", "巡山", "扫黄")
    mt.start()  #  启动线程

4、几个重要的API

并行 : 多个任务同时进行,但python多线程不允许,多进程是允许的

并发 : 多个任务在单个CPU交替执行 ,

串行 : 任务在CPU之间快速切换 , 交替执行

““python
def importantAPI():
print(threading.currentThread()) # 返回当前的线程变量
# 创建五条子线程
t1 = threading.Thread(target=doSth, args=(“巡山”,))
t2 = threading.Thread(target=doSth, args=(“巡水”,))
t3 = threading.Thread(target=doSth, args=(“巡鸟”,))

t1.start()  # 开启线程
t2.start()
t3.start()

print(t1.isAlive())  # 返回线程是否活动的
print(t2.isDaemon())  # 是否是守护线程
print(t3.getName())  # 返回线程名
t3.setName("巡鸟")  # 设置线程名
print(t3.getName())
print(t3.ident)  # 返回线程号

# 返回一个包含正在运行的线程的list
tlist = threading.enumerate()
print("当前活动线程:", tlist)

# 返回正在运行的线程数量(在数值上等于len(tlist))
count = threading.active_count()
print("当前活动线程有%d条" % (count))

““

3、线程冲突

'''
【线程冲突】示例:
多个线程并发访问同一个变量而互相干扰
互斥锁
    状态:锁定/非锁定
    #创建锁
        lock = threading.Lock()
    #锁定
        lock.acquire()
    #释放
        lock.release()
'''
'''
互相锁住对方线程需要的资源,造成死锁局面
递归锁,用于解决死锁的问题,可重复锁
'''
import threading
import time
money = 0

# CPU分配的时间片不足以完成一百万次加法运算,
# 因此结果还没有被保存到内存中就被其它线程所打断
def addMoney():
    global money
    for i in range(1000000):
        money += 1
    print(money)

# 创建线程锁
lock = threading.Lock()

def addMoneyWithLock():
    # print("addMoneyWithLock")
    time.sleep(1)
    global money
    # print(lock.acquire())
    # if lock.acquire():
    #     for i in range(1000000):
    #         money += 1
    # lock.release()
    # 独占线程锁
    with lock:  # 阻塞直到拿到线程锁

        # -----下面的代码只有拿到lock对象才能执行-----
        for i in range(1000000):
            money += 1
        # 释放线程锁,以使其它线程能够拿到并执行逻辑
        # ----------------锁已被释放-----------------

    print(money

# 5条线程同时访问money变量,导致结果不正确
def conflictDemo():
    for i in range(5):
        t = threading.Thread(target=addMoney)
        t.start()

# 通过线程同步(依次执行)解决线程冲突
def handleConflictBySync():
    for i in range(5):
        t = threading.Thread(target=addMoney)
        t.start()
        t.join()  # 一直阻塞到t运行完毕

# 通过依次独占线程锁解决线程冲突
def handleConflictByLock():
    # 并发5条线程
    for i in range(5):
        t = threading.Thread(target=addMoneyWithLock)
        t.start()

if __name__ == '__main__':
    # conflictDemo()
    # handleConflictBySync()
    handleConflictByLock()

4、使用Semaphore调度线程:控制最大并发量

'''
使用Semaphore调度线程:控制最大并发量
'''
import threading
import time
# 允许最大并发量3
sem = threading.Semaphore(3)

def doSth(arg):
    with sem:
        tname = threading.current_thread().getName()
        print("%s正在执行【%s】" % (tname, arg))
        time.sleep(1)
        print("-----%s执行完毕!-----\n" % (tname))
        time.sleep(0.1)

if __name__ == '__main__':

    # 开启10条线程
    for i in range(10):
        threading.Thread(target=doSth, args=("巡山",), name="小分队%d" % (i)).start()
    pass
相关文章
|
3天前
|
安全 调度 Python
探索Python中的并发编程:协程与多线程的比较
本文将深入探讨Python中的并发编程技术,重点比较协程与多线程的特点和应用场景。通过对协程和多线程的原理解析,以及在实际项目中的应用案例分析,读者将能够更好地理解两种并发编程模型的异同,并在实践中选择合适的方案来提升Python程序的性能和效率。
|
1天前
|
Python
|
1天前
|
Java 测试技术 Python
Python的多线程允许在同一进程中并发执行任务
【5月更文挑战第17天】Python的多线程允许在同一进程中并发执行任务。示例1展示了创建5个线程打印"Hello World",每个线程调用同一函数并使用`join()`等待所有线程完成。示例2使用`ThreadPoolExecutor`下载网页,创建线程池处理多个URL,打印出每个网页的大小。Python多线程还可用于线程间通信和同步,如使用Queue和Lock。
14 1
|
2天前
|
数据处理 Python
Python并发编程:实现高效的多线程与多进程
Python作为一种高级编程语言,提供了强大的并发编程能力,通过多线程和多进程技术,可以实现程序的并发执行,提升系统的性能和响应速度。本文将介绍Python中多线程和多进程的基本概念,以及如何利用它们实现高效的并发编程,解决实际开发中的并发性问题。
|
3天前
|
Java Python
Python 内置库 多线程threading使用讲解
本文介绍Python中的线程基础。首先展示了单线程的基本使用,然后通过`threading`模块创建并运行多线程。示例中创建了两个线程执行不同任务,并使用`active_count()`和`enumerate()`检查线程状态。接着讨论了守护线程,主线程默认等待所有子线程完成,但可设置子线程为守护线程使其随主线程一同结束。`join()`方法用于主线程阻塞等待子线程执行完毕,而线程池能有效管理线程,减少频繁创建的开销,Python提供`ThreadPoolExecutor`进行线程池操作。最后提到了GIL(全局解释器锁),它是CPython的机制,限制了多线程并行执行的能力,可能导致性能下降。
12 1
|
3天前
|
消息中间件 程序员 调度
Python并发编程:利用多线程提升程序性能
本文探讨了Python中的并发编程技术,重点介绍了如何利用多线程提升程序性能。通过分析多线程的原理和实现方式,以及线程间的通信和同步方法,读者可以了解如何在Python中编写高效的并发程序,提升程序的执行效率和响应速度。
|
3天前
|
并行计算 安全 测试技术
Python多线程
【4月更文挑战第13天】对比多线程与多进程:多线程适合I/O密集型任务,轻量级但受GIL限制;多进程适用于CPU密集型任务,能实现真正并行。多线程直接共享内存,多进程独立内存,各有优劣。
19 0
|
3天前
|
数据采集 安全 Java
Python的多线程,守护线程,线程安全
Python的多线程,守护线程,线程安全
|
3天前
|
并行计算 数据处理 开发者
Python并发编程:解析异步IO与多线程
本文探讨了Python中的并发编程技术,着重比较了异步IO和多线程两种常见的并发模型。通过详细分析它们的特点、优劣势以及适用场景,帮助读者更好地理解并选择适合自己项目需求的并发编程方式。
|
3天前
|
调度 Python 容器
【python】-详解进程与线程
【python】-详解进程与线程