线程

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秒

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:线程 - Python技术站

(0)
上一篇 2023年4月2日
下一篇 2023年4月2日

相关文章

  • django中的request对象方法

    1.什么是request对象 在django中,当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象;Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。 2.request对象的作用 request对象里面封装了请求时拿到的数据,我们可以通过request.的…

    Python开发 2023年4月2日
    00
  • 文章的评论(跟评论与子评论的制作)

    文章的评论制作 先做跟评论,在做子评论 发表评论框的制作:前端渲染发表评论框: {# 评论功能开始#} {% if request.user.is_authenticated %} <div> <p><span class=”glyphicon glyphicon-comment”>发表评论:</span>&l…

    2023年4月2日
    00
  • 权限类与频率类

    权限类 主要用途:用户登录了,某个接口可能只有超级管理员才能访问,普通用户不能访问 案列:出版社的所有接口,必须登录,而且是超级管理员才能访问 分析步骤 第一步:写一个类,继承BasePermission 第二步:重写has_permission方法 第三步:在方法校验用户时候有权限(request.user就是当前登录用户) 第四步:如果有权限,返回Tru…

    2023年4月2日
    00
  • xadmin的使用

    安装 在项目的虚拟环境下执行 pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2 注意:xadmin对于不同django版本有不同的版本,一定要使用相对应的版本 在app中注册 INSTALLED_APPS = [ # … # xadmin主体模块 ‘xadmin’, # …

    Python开发 2023年4月2日
    00
  • 函数的递归

    1.函数的递归的定义 函数的递归调用:是函数嵌套调用的一种特殊形式 具体是指:在调用一个函数的过程中又直接或者间接的调用到本身,是一个死循环,最大递归是1000次,超出之后报错。 2.函数递归的调用 # 直接调本身 def f1(): print(‘是我还是我’) f1() f1() # 间接调用 def f1(): print(‘f1’) f2() def…

    Python开发 2023年4月2日
    00
  • python基础(待补充)

    第一篇:计算机的基础知识 编程语言的介绍    计算机介绍和五大组成 平台与软件跨平台介绍 CS、BS架构和网络通信协议 操作系统的介绍 cpu详解 存储器详解 操作系统启动流程和BIOS介绍 关于编辑器和解释型编译型语言 第二篇:python环境的搭建 python介绍和解释器的安装(暂略) python程序的运行方式和步骤 集成开发环境和虚拟环境介绍 第…

    Python开发 2023年4月2日
    00
  • 基础数据类型之集合

    1.集合的定义 在{}内用逗号分开多个元素,多个元素满足以下三个条件: 1.集合元素必须是不可变类型2.集合元素无序3.集合内元素没有重复(打印出来会自动去重) d = {} 默认是定义空字典 需要定义空集合,需要使用s = set() 2,集合的作用 (1)关系运算 # 如何取出这两个人共同的朋友呢? friend1=[‘zhang’,’yang’,’li…

    Python开发 2023年4月2日
    00
  • 文章的点赞点踩制作

    文章的添加 博客园打开需要拷贝的文章,右键检查–》选择cnblogs_post_body这一个div,然后复制outer HTML到admin后台文章表里面 最后需要在文章详情页的文章内容那一行添加一个|safe 点赞点踩制作 前端样式: 不会写,直接拷贝博客园的点赞点踩html和css样式 {# 点赞点踩样式开始:复制博客园的点赞点踩样式,拷贝其对应的o…

    2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部