Python多线程入门到放弃

在这里插入图片描述
在生产者消费者的中, 我们经常会遇到任务调度的情况, 这时候常用的解决方案就是使用多线程来解决相关的调度问题。

多线程扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。
线程(Thread)也被成为轻量级的进程,线程是进程执行的单元,线程在程序中是独立的、并发的执行流
当进程被初始化后,主线程就被创建了。绝大数应用程序只需要有一个主线程,但也可以在进程内创建多条的线程,每个线程也是相互独立的。
一个进程可以拥有多个线程,一个线程必须有一个父进程。
线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源,因此编程更加方便。
线程是独立运行的,它并不知道进程中是否还有其他的线程存在。线程的执行是抢占式的,即:当前运行的线程在任何时候都有可能被挂起,以便另外一个线程可以运行。
一个线程可以创建和撤销另一个线程,同一个进程中多个线程之间可以并发执行。
线程的调度和管理由进程本身负责完成。
归纳而言:操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程
线程创建的初期就是为了解决系统资源分配和效率问题。为的是使用最小的代价,实现最大的资源利用率。
在这里插入图片描述

Python多线程的实现方式:

一、通过实现Thread来实现
import threadingimport time

def run(n):
    print("task", n)
    time.sleep(1)
    print('2s')
    time.sleep(1)
    print('1s')
    time.sleep(1)
    print('0s')
    time.sleep(1)

if __name__ == '__main__':
    t1 = threading.Thread(target=run, args=("t1",))
    t2 = threading.Thread(target=run, args=("t2",))
    t1.start()
    t2.start()

----------------------------------
>>> task t1
>>> task t2
>>> 2s
>>> 2s
>>> 1s
>>> 1s
>>> 0s
>>> 0s
二、继承Thread类
import threadingimport time

class MyThread(threading.Thread):
    def __init__(self, n):
        super(MyThread, self).__init__()  # 重构run函数必须要写
        self.n = n

    def run(self):
        print("task", self.n)
        time.sleep(1)
        print('2s')
        time.sleep(1)
        print('1s')
        time.sleep(1)
        print('0s')
        time.sleep(1)

if __name__ == "__main__":
    t1 = MyThread("t1")
    t2 = MyThread("t2")
    t1.start()
    t2.start()

----------------------------------
>>> task t1
>>> task t2
>>> 2s
>>> 2s
>>> 1s
>>> 1s
>>> 0s
>>> 0s

上面的线程实现方式都是没有返回值的,单纯的只是实现了调用其他函数的功能,一般而言我们在调用方法和实现对象的时候都是为了得到一定的返回值,那么这个时候对于线程来说就需要有一定的返回值才能实现对应的功能。这里写上我常用的封装类:

需求:

实现线程调度 带有返回值

import threading
import time


class ThreadClass(threading.Thread):
    def __init__(self, func, args=()):
        super(ThreadClass, self).__init__()
        self._func = func
        self._args = args
        self._result = None

    def run(self):
        if self._args == ():
            self._result = self._func()
        else:
            self._result = self._func(*self._args)

    def get_result(self):
        threading.Thread.join(self)  # 等待线程执行完毕
        try:
            return self._result
        except Exception:
            return None

使用起来也非常简单:

from ThreadClass import ThreadClass
    
    def plus(a: int, b: int) -> int:    
        return a+b
    
    task = ThreadClass(plus, (1, 2))
    task.start()
    result = task.get_result()
    print(result)

不论按照上面哪一种方式实现多线程,其实都有一个比较严重的问题就是效率。
我们知道在Python中的多线程实现方式其实有点像一个人同时在做两件事,你只能同时切换着来完成,这种方式在不同线程切换的时候效率决定了一切。
在量化交易系统中,尤其是低延迟的交易系统中,有时候毫秒之间就能决定一个订单的成败。效率在这种情况下显得尤为重要。

针对Python在线程效率方面其实可以归纳为以下两点:

  1. CPU密集型代码(各种循环处理、计算等等),在这种情况下,由于计算工作多,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换当然是需要消耗资源的),所以python下的多线程对CPU密集型代码并不友好。
  2. IO密集型代码(文件处理、网络爬虫等涉及文件读写的操作),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。所以python的多线程对IO密集型代码比较友好。

总结来说,其实并不是Python的多线程不好,也不是实现不了我们高效的功能,只是在效率上不能够满足我们的需求,从开发需求上面来说,我们不求更好,但求更加适合的功能。所以这时候我们并不能够满足我们的基础需求。如果想要发挥服务器的多核特性,这里还是建议使用多进程的方式来实现,在多进程中,每个独立的进程都会分配独立的GIL来运行,并不会相互有任何干扰,这样就可以实现真正意义上的并行执行,在python中,多进程的执行效率优于多线程(仅仅针对多核CPU而言)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值