首页 > 其他分享 >多线程

多线程

时间:2024-04-09 20:48:00浏览次数:19  
标签:__ run Thread 线程 print 多线程 def

多线程

一、多线程理论

[1]什么线程

  • 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
  • 线程顾名思义,就是一条流水线工作的过程
    • 一条流水线必须属于一个车间,一个车间的工作过程是一个进程
    • 车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
    • 流水线的工作需要电源,电源就相当于CPU
  • 所以进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是CPU上的执行单位。
  • 多线程(即多个控制线程)的概念是在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
  • 例如
    • 北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。

[小结]

  • 每一个进程必定自带一个线程
  • 进程:资源单位
    • 起一个进程仅仅只是 在内存空间中开辟出一块独立的空间
  • 线程:执行单位
    • 真正被CPU执行的其实是进程里面的线程
    • 线程指的就是代码的执行过程,执行代码中所需要使用到的资源都找所在的进程索要
  • 进程和线程都是虚拟单位,只是为了我们更加方便的描述问题

[2]线程的创建开销

(1)创建进程的开销要远大于创建线程

  • 如果我们的软件是一个工厂
  • 该工厂有多条流水线
  • 流水线工作需要电源
  • 电源只有一个即CPU(单核CPU)
    • 一个车间就是一个进程
      • 一个车间至少一条流水线(一个进程至少一个线程)
    • 创建一个进程
      • 就是创建一个车间(申请空间,在该空间内建至少一条流水线)
    • 而建线程
      • 就只是在一个车间内造一条流水线
      • 无需申请空间,所以创建开销小

(2)进程之间是竞争关系,线程之间是协作关系

  • 车间直接是竞争/抢电源的关系,竞争
    • 不同的进程直接是竞争关系
    • 不同的程序员写的程序运行的迅雷抢占其他进程的网速
    • 把其他进程当做病毒干死
  • 一个车间的不同流水线式协同工作的关系
    • 同一个进程的线程之间是合作关系,是同一个程序写的程序内开启动
    • 迅雷内的线程是合作关系,不会自己干自己

二、多线程操作

[1]threading模块介绍

  • multiprocess模块的完全模仿了threading模块的接口
  • 二者在使用层面,有很大的相似性,因而不再详细介绍

[2]开启线程的两种方式

  • 开启线程不需要在main下面执行代码,直接书写即可
  • 但是我们还是习惯性的将启动命令写在main下面

(1)方式一:直接调用 Thread 方法

from threading import Thread
import time


def run(i):
    print(f'这里是子线程{i}开始!')
    time.sleep(1)
    print(f'这里是子线程{i}结束!')


if __name__ == '__main__':
    print('主程序开始运行!')
    for i in range(1, 3):
        t = Thread(target=run, args=(i,))
        t.start()
        t.join()
    print('主程序结束运行!')

"""
主程序开始运行!
这里是子线程1开始!
这里是子线程1结束!
这里是子线程2开始!
这里是子线程2结束!
主程序结束运行!
"""

(2)方式二:继承 Thread 父类

from threading import Thread
import time


class MyThread(Thread):
    def __init__(self, i):
        super().__init__()
        self.i = i

    def run(self):
        print(f'这里是子线程{self.i}开始!')
        time.sleep(1)
        print(f'这里是子线程{self.i}结束!')


def main():
    print('主程序开始运行!')
    for i in range(1, 3):
        t = MyThread(i)
        t.start()
        t.join()
    print('主程序结束运行!')


if __name__ == '__main__':
    main()


"""
主程序开始运行!
这里是子线程1开始!
这里是子线程1结束!
这里是子线程2开始!
这里是子线程2结束!
主程序结束运行
"""

[3]一个进程下开启多个线程和多个子进程的区别

(1)开启速度的比较

  • 线程的开启速度较快
from multiprocessing import Process
from threading import Thread
import time


def run():
    print('开启成功!')


def timer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        res = func(*args, *kwargs)
        print(f'所用时间{time.time() - start_time}s')
        return res

    return inner


@timer
def the_process():
    p = Process(target=run)
    p.start()
    p.join()


@timer
def the_thread():
    p = Thread(target=run)
    p.start()
    p.join()


if __name__ == '__main__':
    the_process()
    # 开启成功!
    # 所用时间0.19514107704162598s
    the_thread()
    # 开启成功!
    # 所用时间0.001990795135498047s

(2)多线程与有进程的PID

import os
from multiprocessing import Process
from threading import Thread


def run():
    print('开启成功!', os.getpid())


def the_process():
    p1 = Process(target=run)
    p2 = Process(target=run)
    p1.start()
    p2.start()
    p1.join()
    p2.join()


def the_thread():
    p1 = Thread(target=run)
    p2 = Thread(target=run)
    p1.start()
    p2.start()
    p1.join()
    p2.join()


if __name__ == '__main__':
    the_process()
    # 开启成功! 21372
    # 开启成功! 11148
    # 多个进程就会有多个不同的pid
    the_thread()
    # 开启成功! 14972
    # 开启成功! 14972
    # 多个线程就使用通一个pid

[4]线程对象的join方法

  • 线程的join方法和进程的join方法是一样的
from threading import Thread
import time


def run():
    print('子线程开始!')
    time.sleep(2)
    print('子线程结束!')


def the_thread():
    p = Thread(target=run)
    p.start()
    p.join()


if __name__ == '__main__':
    print('主程序开始运行!')
    the_thread()
    print('主程序结束运行!')


"""
主程序开始运行!
子线程开始!
子线程结束!
主程序结束运行!
"""

[5]线程对象属性及其他方法

(1)获取当前进程的名字current_thread

from threading import Thread, current_thread


def run():
    print('子线程开始!')
    print(f'当前运行的程序名:{current_thread().name}')
    print('子线程结束!')


def main():
    t = Thread(target=run)
    t.start()
    t.join()
    print(f'当前运行的程序名:{current_thread().name}')


if __name__ == '__main__':
    main()


"""
子线程开始!
当前运行的程序名:Thread-1 (run)
子线程结束!
当前运行的程序名:MainThread
"""

(2)统计当前活跃的线程数active_count

from threading import Thread, current_thread, active_count


def run():
    print('子线程开始!')
    print(f'当前运行的程序名:{current_thread().name}')
    print('子线程结束!')


def main():
    t = Thread(target=run)
    t.start()
    t.join()
    print(f'当前活跃的线程数: {active_count()}')
    print(f'当前运行的程序名:{current_thread().name}')


if __name__ == '__main__':
    main()

"""
子线程开始!
当前运行的程序名:Thread-1 (run)
子线程结束!
当前活跃的线程数: 1
当前运行的程序名:MainThread
"""

三、守护线程

[1]主线程死亡,子线程未死亡

  • 主线程结束运行后不会马上结束,而是等待其他非守护子线程结束之后才会结束
  • 如果主线程死亡就代表者主进程也死亡,随之而来的是所有子线程的死亡
 from threading import Thread
import time


def run():
    print('子进程开始!')
    time.sleep(1)
    print('子进程结束!')


if __name__ == '__main__':
    print('主程序开始运行!')
    t = Thread(target=run)
    t.start()
    print('主进程结束运行!')


"""
主程序开始运行!
子进程开始!
主进程结束运行!
子进程结束!
"""

[2]主线程死亡,子线程也死亡

from threading import Thread
import time


def run():
    print('子进程开始!')
    time.sleep(1)
    print('子进程结束!')


if __name__ == '__main__':
    print('主程序开始运行!')
    t = Thread(target=run)
    # 开启守护线程
    t.daemon = True
    t.start()
    print('主进程结束运行!')


# 当主线程死亡时,子线程必须强制死亡
"""
主程序开始运行!
子进程开始!
主进程结束运行!
"""

四、线程的互斥锁

  • 当没有设置互斥锁时,当所有线程都阻塞一秒之后,所以线程都同时拿到了100,都只减了1,所以结果会是99
from threading import Thread
import time

money = 100


def run():
    global money

    temp = money
    time.sleep(1)
    money = temp - 1


def main():
    t_list = []
    for i in range(20):
        t = Thread(target=run)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    print(money)


if __name__ == '__main__':
    main()  # 99

  • 设置了互斥锁之后,虽然牺牲了效率,但保证了修改数据的安全性和可靠性
from threading import Thread, Lock
import time

money = 100

lock = Lock()


def run():
    lock.acquire()
    global money

    temp = money
    time.sleep(1)
    money = temp - 1
    lock.release()


def main():
    t_list = []
    for i in range(20):
        t = Thread(target=run)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    print(money)


if __name__ == '__main__':
    main()  # 80

标签:__,run,Thread,线程,print,多线程,def
From: https://www.cnblogs.com/taoyuanshi/p/18124730

相关文章

  • Java基础知识-面向对象编程(OOP)-Java集合框架-多线程和并发-Spring框架
    Java基础知识:Java的四种基本数据类型是:byte、short、int、long(整数类型)、float、double(浮点类型)、char(字符类型)、boolean(布尔类型)。它们之间的区别主要在于占用的内存大小和表示范围不同。Java中的String是不可变的意味着一旦String对象被创建,它的值就不能被修改。这意味着St......
  • 简述多线程中的锁与sleep
    面试中经常被问到,在多线程/加锁环境下使用sleep可能出现的问题,首先总结一下这些问题基本都出自sleep不会释放锁这一点(与wait()截然相反)。1sleep可能会引发的问题线程持有锁时休眠:当一个线程在持有锁的情况下调用sleep()时,它会在睡眠时仍保持锁的状态,此时其他线程将无法访......
  • 多线程面试要点
    一、线程的基础知识1、线程和进程的区别一个线程就是一个指令流,将指令流中的一条条指令以一定顺序交给CPU执行一个进程之内可以分为一到多个线程。二者对比进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务。不同的进程使用不同的内存空间,在当前进程......
  • JavaEE初阶Day 5:多线程(3)
    目录Day5:多线程(3)1.join2.再谈sleep3.线程的状态4.线程安全问题Day5:多线程(3)多线程在整个编程中都是非常核心非常重要的话题多核CPU客观的主流的需求多线程这里还是有一定难度/不少注意事项的回顾Thread创建的写法继承Thread,重写run实现Runnable,重写run......
  • 30_多线程
    多线程多线程简介​ 线程,是一种允许一个正在运行的程序同时执行不止一个任务的机制。不同线程看起来是并行运行的;Linux操作系统对线程进行异步调度,不断中断它们的执行以给其它线程执行的机会。​ 线程与进程的区别:线程是进程中的一个独立并发执行的路径,进程退出时,线程也会退......
  • Java多线程
    Process进程系统资源分配的单位Thread线程CPU调度和执行的单位1.继承Thread类packagedemo01;//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程//线程开启不一定立即执行,由cpu调度publicclassTestThread1extendsThread{@Overridep......
  • 多线程
    参考转载自:.NET多线程-Broder-博客园(cnblogs.com)一、进程和线程定义进程:一个程序在服务器上运行时,占用的计算机资源合集,就是进程。线程:是程序能够独立运行的最小单位。线程具有进程所具有的特征,所以线程又叫轻型进程。二、多线程线程分为原生线程和托管线程,原生线程生......
  • 多线程环境中使用MyBatis时避免出现没有token的问题
    //很重要,在多线程没有token下面三行可以解决mybatis方法报错//1.通过当前的WebUtil.getRequest()获取Servlet请求的属性ServletRequestAttributesservletRequestAttributes=newServletRequestAttributes(WebUtil.getRequest());//2.将获取到的Servlet请求属性设置......
  • C++多线程:async、future、packaged_task、promise、shared_future的学习与使用(九)
    1、异步任务线程异步线程的概念:异步:就是非同步,同步就是必须一个一个的执行,异步可以两个事情一起干异步线程:异步线程就相当于把非关联的两件事分开找两个线程去执行,而分开的那个就是异步线程举例:例如登录信息,用户登录完毕主线程肯定是需要去及时响应用户的请求的,而系统设......
  • 【JAVA】JAVA多线程基础4
    目录一、synchronized关键字特性1、互斥2、刷新内存3、可重入二、synchronized使用方法1、直接修饰普通方法2、修饰静态方法3、修饰代码块三、volatile关键字一、synchronized关键字特性1、互斥synchronized会起到互斥效果,某个线程执行到某个对象的synchronized......