首页 > 其他分享 >线程

线程

时间:2022-08-26 14:07:02浏览次数:40  
标签:__ name 线程 time print import

1. 什么是线程

线程就是进程里面的执行单位,每一个进程肯定都自带一个线程,真正被cpu执行的是线程,线程是代码的执行过程,该过程中需要的资源都找对应的进程要

进程是资源的单位,线程是执行单位!
image

补充:同一个进程里面的多个线程资源是共享的!

2. 为啥要有线程

一个进程里面可以开设多个线程,而开设线程是不需要申请内存空间的(进程需要),因此,开设线程的消耗远远小于进程!

3. 如何使用线程

3.1 创建线程的第一种方式(掌握)

from threading import Thread # 导入线程模块
from multiprocessing import Process
import time

# 定义子线程函数
def func(name):
    print('%s 来啦'%name)
    time.sleep(2)
    print('%s走了'%name)

# 创建线程不需要写在main下,但是我们还是习惯性的把它写在main下
if __name__ == '__main__':
    # 创建线程对象
    t = Thread(target=func,args=('zhang',))
    # p = Process(target=func,args=('zhang',))
    # p.start()
    t.start() # 启动线程
    # 线程和进程的开启相比,线程更加的块,线程不需要开辟内存空间
    print('主')

3.2 创建线程的第二种方式

from threading import Thread

# 1.创建一个类,该类继承线程类
class MyThread(Thread):
    # 第二种方法需要给子线程添加参数的方法是类中有一个双init方法
    # 先继承父类的双init方法,然后在书写需要自己加入的参数,这样就可以在run函数里调用参数了
    def __init__(self,name):
        super().__init__()
        self.name = name
    # 2.该类中子线程函数名必须是run
    def run(self):
        print('我是线程%s'%self.name)

if __name__ == '__main__':
    # 3.创建子线程对象
    t = MyThread('zhang')
    # 4.开启子线程
    t.start()
    print('主')

3.3 线程中的join方法

join方法的含义是:主线程等待子线程运行完毕再执行

from threading import Thread # 导入线程模块
from multiprocessing import Process
import time

def func(name):
    print('%s 来啦'%name)
    time.sleep(1)
    print('%s走了'%name)

if __name__ == '__main__':
    t = Thread(target=func,args=('zhang',))
    t.start()
    t.join() # join方法的含义是:主线程等待子线程运行完毕再执行
    print('主')

3.4 线程对象和其他方法

from threading import Thread,active_count,current_thread
import time,os

def func():
    # os.getpid()获取当前线程的进程id,主线程和子线程id相同
    # print('hello',os.getpid())
    # current_thread().name获取当前线程的线程名
    print('hello', current_thread().name)
    time.sleep(2)

if __name__ == '__main__':
    t = Thread(target=func)
    t.start()
    # print('主',current_thread().name)
    # active_count() 获取当前活跃的线程数量
    print('主',active_count())

3.5 守护线程

from threading import Thread
import time

def func(name):
    print('%s来啦'%name)
    time.sleep(2)
    print('%s走了'%name)

if __name__ == '__main__':
    t = Thread(target=func,args=('zhang',))
    t.daemon = True # 守护主线程,主线程结束之后该子线程也会结束
    t.start()
    print('主')
    """
    主线程一般不会自动结束,它会等待所有非守护线程结束之后再结束
    因为主线程结束意外着主进程也结束了,这样其他线程就无法调用主进程的资源了
    """

3.6 线程的互斥锁

from threading import Thread,Lock
import time

momey = 100
# 加一把锁
metua = Lock()

def func():
    global momey
    # 在获取数据的前面加一把锁
    metua.acquire()
    num = momey
    time.sleep(0.01)
    momey = num -1
    # 释放该锁
    metua.release()

if __name__ == '__main__':
    t_list = []
    for i in range(100):
        t = Thread(target=func)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(momey)

3.7 GIL锁与互斥锁

GIL需要知道的重点:

	1.GIL不是python的特点而是CPython解释器的特点
	2.GIL是保证解释器级别的数据的安全
	3.GIL会导致同一个进程下的多个线程的无法同时执行即无法利用多核优势(******)
	4.针对不同的数据还是需要加不同的锁处理 
	5.解释型语言的通病:同一个进程下多个线程无法利用多核优势

GIL锁与互斥锁的区别

from threading import Thread,Lock
import time

momey = 100
# 加一把锁
metua = Lock()

def func():
    global momey
    # 在获取数据的前面加一把锁
    metua.acquire()
    num = momey
    time.sleep(0.01) # 注意:这里sleep是在模拟网络延迟。如果假设没有网络延迟,没有互斥锁LOCK,得到money的结果也应为0,因为一个进程里有一个cpython解释器,cpython解释器有一个GIL锁的概念,同一个进程下的多个线程无法同时执行,它们必须去抢同一个GIL锁,没有网络延迟(没有IO),GIL锁就会直到数据操作完在释放,保证了多个线程执行的数据安全;但是实际上是有网络延迟的,就比如sleep,这时GIL锁就会直接释放掉,导致得到的money=99
    momey = num -1
    # 释放该锁
    metua.release()

if __name__ == '__main__':
    t_list = []
    for i in range(100):
        t = Thread(target=func)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(momey)

3.8多线程与多进程的比较

当需要处理的工作大都是是计算密集型时优先考虑多进程(较好的利用多核优势)
当需要处理的工作大都是IO密集型时优先考虑多线程(节省空间消耗)

计算密集型就是计算处理偏多
IO密集型就是用户输入输出偏多

# 当处理的工作是计算密集型的时候,好像现在多线程比多进程有优势???待验证!
from multiprocessing import Process
from threading import Thread
import os,time

def work():
    res = 0
    for i in range(1000000):
        res *= i

if __name__ == '__main__':
    list = []  # 将下面for循环每次开设的线程/进程对象存储起来
    print(os.cpu_count()) # 获取当前计算机的CPU个数
    start_time = time.time()  # 获取开始时间
    for i in range(16): # for循环开设进程/线程
        # p = Process(target=work)
        p = Thread(target=work)
        p.start()
        list.append(p) # 将每次开设的进程对象添加到列表里
    for p in list: # 变量进程对象
        p.join() # 守护主进程/线程
    print(time.time()-start_time)
    # 计算密集型 多进程用时1.8412911891937256秒  多线程用时0.318603515625秒

标签:__,name,线程,time,print,import
From: https://www.cnblogs.com/suncolor/p/16618324.html

相关文章

  • Linux 线程控制
    Linux线程控制线程属性同步原语属性多线程间如何保持数据私有性基于进程的系统调用如何与线程交互线程限制可通过sysconf函数查询线程限制。注意:有些os下使用s......
  • 多线程知识
    一、线程概述:线程可以说是一个应用程序或者说是一个软件;线程是一个进程中的场景(进程好比一个公司,线程好比公司里的员工)二、进程与线程的关系一个进程可以创建多......
  • 线程池ThreadPoolExecutor
    线程池ThreadPoolExecutor1、线程池介绍1.1线程池概念Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关......
  • 彻底了解线程池的原理——40行从零开始自己写线程池
    前言在我们的日常的编程当中,并发是始终离不开的主题,而在并发多线程当中,线程池又是一个不可规避的问题。多线程可以提高我们并发程序的效率,可以让我们不去频繁的申请和释放......
  • Thread+isInterrupted+自定义(停止线程)
    1.interrupt终端线程publicstaticvoidmain(String[]args)throwsInterruptedException{//创建子线程Threadthread1=newThread(()->{......
  • 面经-并发-对ThreadLocal(线程隔离)的理解
    ThreadLocal作用:1.线程隔离。线程间:ThreadLocal可实现资源对象的线程隔离,让每个线程各用各的资源对象,避免争用引发的线程安全问题。2.资源共享。线程内:ThreadLocal同时实......
  • 操作系统学习笔记5 | 用户级线程 && 内核级线程
    在上一部分中,我们了解到操作系统实现多进程图像需要组织、切换、考虑进程之间的影响,组织就是用PCB的队列实现,用到了一些简单的数据结构知识。而本部分重点就是进程之间的切......
  • 历时2月,动态线程池 DynamicTp 发布里程碑版本 V1.0.8
    关于DynamicTpDynamicTp是一个基于配置中心实现的轻量级动态线程池管理工具,主要功能可以总结为动态调参、通知报警、运行监控、三方包线程池管理等几大类。经过多个版......
  • 面经-并发-线程状态
    java中的线程状态   线程状态_五种状态vs六种状态五种状态:操作系统层面分到CPU时间的:运行可以分到CPU时间的:就绪分不到CPU时间的:阻塞  Java中的Runnable......
  • 使用SpringBoot内置多线程
    SpringBoot使用多线程一概述1为什么使用多线程  在我们开发系统过程中,经常会处理一些好费时间的任务(如向数据库中插入上百万数据,将会导致系统阻塞),这个时候就会自然......