线程理论

进程
进程其实是资源单位 标示开辟一块内存空间
线程
线程才是执行单位 表示真正的代码质量 注意:进程是资源分配的最小单位,线程是CPU调度的最小单位.
   每一个进程中至少有一个线程。  进程可以比喻为车间 线程表示车间里面的流水线
一个进程内至少包含一个线程(主线程) 1.一个进程内可以开设多个线程
2.同一个进程下的多个线程数据是共享的 数据是可以互相更改使用的 3.进程与线程的区别
创建进程的消耗远远大于线程, 进程越多cpu越累
线程的运行速度远远大于进程 线程的消耗较小

创建线程的两种方式

from threading import Thread
from multiprocessing import Process
import time def task(name):
print(f'{name} is running')
time.sleep(2)
print(f'{name} is over') if __name__ == '__main__': for i in range(20):
t = Thread(target=task, args=('moon',))
# 创建一个线程 t.start()
print('我是主线程') 通过类创建多线程: class My_Thread(Thread):
def __init__(self,name):
super().__init__()
self.name = name def run(self):
print(f'{self.name} is running')
time.sleep(2)
print(f'{self.name} is over') t = My_Thread('moon') t.start

线程的诸多特性

线程同进程很多方法相同
1.join 方法 # 等待线程进行结束
2.current_therad() # 返回当前的线程变量。
3.active_count() # 返回正在运行的线程数量
4.setDaemon(True) # 设置守护线程
5.isAlive() # 返回线程是否活动的

GIL全局解释器

# 官方文档对GIL的解释
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces. '''
1.在cpython解释器中存在全局解释器锁简称 GIL
python解释器的类型:CPython,JPython Pypython(常用C解释器)
2.GIL本质其实就是一把互斥锁 用来阻止同一个进程内多个线程同时执行的
3.GIL的存在是因为CPython解释器中内存管理的线程不是安全的,由于python的垃圾回收线程
可能导致同线程并行,垃圾回收线程出现错误,线程如果同时运行,当一个数据还没有被绑定赋值,然后垃圾回收机制也同步在运行,导致可能数据被当作垃圾回收了
''' GIL不是python的特点,而是Cpython解释器的特点
GIL是保证解释器级别的数据安全,是不同线程之间的锁
针对不同的数据还是要加不同的锁处理

验证GIL存在

from threading import Thread

num = 50

def task():
global num
num -= 1 t_list= [] for i in range(1,50):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join() print(num)

GIL与普通互斥锁的区别

from threading import Thread, Lock
import time mutex = Lock()
money = 50 def task():
global money
mutex.acquire()
tmp = money
time.sleep(0.2)
money = tmp - 1
mutex.release() if __name__ == '__main__':
t_list = []
for i in range(50):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(money) '''
首先多线程 每个线程需要去抢到GIL 有了GIL才会执行
然后 如果抢到了 GIL然后进入了IO操作 GIL就会自动释放,
所以如果不加普通的互斥锁,还是会导致所有的线程拿到的都是同一份数据 如果有了互斥锁,那就不会影响,因为每个线程都需要先抢到GIL 然后
拥有GIL锁的线程也会抢到互斥锁,当进入IO操作时,其他线程有了GIL但是
也没办法拿到互斥锁 所以这样就可以保证线程一个一个运行 '''

同一个进程下多线程是否有优势

'''
多线程是否有用要看具体情况,
IO密集型/计算密集型
''' 计算密集型: 多进程合适 可以异步操作缩短计算总耗时 IO密集型: 多线程合适 更加节省资源 计算密集型:
from multiprocessing import Process
import os,time
from threading import Thread def work():
res = 0
for i in range(1,828888):
res +=i if __name__ == '__main__':
l = []
start_time = time.time()
for i in range(8):
p = Process(target=work)
p.start()
l.append(p)
for p in l:
p.join()
print(time.time() - start_time) # 14s if __name__ == '__main__':
l = []
start_time = time.time()
for i in range(8):
t = Thread(target=work)
t.start()
l.append(t)
for t in l:
t.join()
print(time.time() - start_time) # 42s !!!得出结论 计算密集型 多进程比较快,多线程慢了大概3倍 !!! IO操作密集时: from multiprocessing import Process
import os,time
from threading import Thread def work():
time.sleep(1) if __name__ == '__main__':
l = []
start_time = time.time()
for i in range(400):
p = Process(target=work)
p.start()
l.append(p)
for p in l:
p.join()
print(time.time() - start_time) # 6.6 if __name__ == '__main__':
l = []
start_time = time.time()
for i in range(8):
t = Thread(target=work)
t.start()
l.append(t)
for t in l:
t.join()
print(time.time() - start_time) # 1s !!!得出结论 IO密集型 多线程比较快,多线程效率太低 !!!

死锁现象

当我们自己加锁时,必须知道 抢锁后立即释放锁,因为当你在多线程多进程操作锁的时候极容易产生锁死现象,整个程序卡死
from threading import Lock, Thread
import time mutexA = Lock()
mutexB = Lock() class MyThread(Thread):
def run(self):
self.func1()
self.func2() def func1(self):
mutexA.acquire()
print('1')
mutexB.acquire()
print('2')
mutexB.release()
print('3')
mutexA.release()
print('4') def func2(self):
mutexB.acquire()
print('5')
time.sleep(2)
mutexA.acquire()
print('6')
mutexB.release()
mutexA.release() if __name__ == '__main__':
for i in range(10):
t = MyThread()
t.start()

信号量

信号量在不同的阶段可能对应不同的技术点
在并发编程中 信号量指的是锁! 在python并发编程中信号量相当于多把互斥锁(公共厕所) from threading import Thread, Lock, Semaphore
import time
import random sp = Semaphore(5) # 一次性产生五把锁 class MyThread(Thread):
def run(self):
sp.acquire()
# 同时抢5把锁
print(self.name)
time.sleep(random.randint(1, 3))
sp.release()
# 有完成就释放 for i in range(20):
t = MyThread()
t.start()

Event事件

一些进程/线程需要等待另外一些进程/线程运行完毕之后才能运行,类似于红绿灯,可以控制哪些进程先进行 哪些后进行

from threading import Thread, Event
import time event = Event() # 类似于造了一个红绿灯 def light():
print('红灯亮着的 所有人都不能动')
time.sleep(3)
print('绿灯亮了 油门踩到底 给我冲!!!')
event.set() def car(name):
print('%s正在等红灯' % name)
event.wait()
print('%s加油门 飙车了' % name) t = Thread(target=light)
t.start()
for i in range(20):
t = Thread(target=car, args=('熊猫PRO%s' % i,))
t.start() event.wait() # 等待 有了event.set()运行后才执行

多线程/GIL全局锁的更多相关文章

  1. python GIL 全局锁,多核cpu下的多线程性能究竟如何?

    python GIL 全局锁,多核cpu下的多线程性能究竟如何?GIL全称Global Interpreter Lock GIL是什么? 首先需要明确的一点是GIL并不是Python的特性,它是在实现 ...

  2. [ Python - 11 ] 多线程及GIL全局锁

    1. GIL是什么? 首先需要明确的一点是GIL并不是python的特性, 它是在实现python解析器(Cpython)时所引入的一个概念. 而Cpython是大部分环境下默认的python执行环境 ...

  3. 网络编程之多线程——GIL全局解释器锁

    网络编程之多线程--GIL全局解释器锁 一.引子 定义: In CPython, the global interpreter lock, or GIL, is a mutex that preven ...

  4. 并发编程-线程-死锁现象-GIL全局锁-线程池

    一堆锁 死锁现象 (重点) 死锁指的是某个资源被占用后,一直得不到释放,导致其他需要这个资源的线程进入阻塞状态. 产生死锁的情况 对同一把互斥锁加了多次 一个共享资源,要访问必须同时具备多把锁,但是这 ...

  5. [Python 多线程] GIL全局解释器锁 (十三)

    Queue 标准库queue模块,提供FIFO(先进先出)的Queue.LIFO(后进先出)的队列.优先队列. Queue类是线程安全的,适用于多线程间安全的交换数据.内部使用了Lock和Condit ...

  6. python 并发编程 多线程 GIL全局解释器锁基本概念

    首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念. 就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码. ...

  7. TCP并发、GIL全局锁、多线程讨论

    TCP实现并发 #client客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while T ...

  8. Python-多线程之消费者模式和GIL全局锁

    一.生产者和消费者模式 什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯, 所以生产者生产完数据之后不 ...

  9. GIL全局锁测试

    基础知识:https://www.cnblogs.com/SuKiWX/p/8804974.html 测试环境 python3.7默认解释器(cpython) cpu为四核 测试代码 #! /usr/ ...

  10. [py]GIL(全局解释器锁):多线程模式

    在多线程 时同一时刻只允许一个线程来访问CPU,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL 参考 Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务.多个P ...

随机推荐

  1. rabbitmq的内存节点和磁盘节点

    RabbitMQ集群里有内存节点与磁盘节点之分. 所谓内存节点,就是将元数据(metadata)都放在内存里,磁盘节点就是放在磁盘上.(内存节点将全部的队列,交换器,绑定关系,用户,权限,和vhost ...

  2. Docker 查看容器映射路径

    使用以下命令:container_name 是容器的名字,也可以写容器的ID. docker inspect container_name | grep Mounts -A 20 docker ins ...

  3. esp-idf 安装(Windows )

    esp32的开发有两种环境,分别是 Arduino 和 esp32-idf. Arduino 是在 esp32-idf 基础上进行封装的,虽然使用起来比较方便,但是能自由更改的就变少了,适合新手使用. ...

  4. Tubian系统无法打开Android子系统的解决方法

    打开Konsole,Konsole在程序菜单(左下角Logo)-系统中 输入: sudo nano /var/lib/waydroid/waydroid.cfg 回车 按方向键,把光标移动到[prop ...

  5. 洛谷P1884 [USACO12FEB]Overplanting S (矩形切割)

    一种矩形切割的做法: 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const in ...

  6. Windows开启关闭测试模式的方法(含开启测试模式失败的解决办法)

    前言:           内含:Windows开启关闭测试模式的方法.开启测试模式失败的解决办法.win10进入bios的方式.BitLocker恢复方式.           对于互联网从业者来说 ...

  7. springboot+vue 实现校园二手商城(毕业设计一)

    1.功能划分 2.实现的效果 2.1 登录页面 2.2 注册页面 2.3 商城首页 2.4 商品详情 2.5 购物车 2.6 订单 2.7 在线交流 2.8 公告信息 2.9 个人信息 3.后台管理界 ...

  8. pip cmd下载速度慢解决方案

    cmd下载速度慢不是电脑问题,而是下载的网站有网速限制,如pip,虽然没被墙,但由于是外网,网速极差,经常是几KB一秒,所以我们可以采用镜像服务器,即在命令后加上 -i https://pypi.tu ...

  9. 什么是ForkJoin?看这一篇就能掌握!

    摘要:ForkJoin是由JDK1.7之后提供的多线程并发处理框架. 本文分享自华为云社区<[高并发]什么是ForkJoin?看这一篇就够了!>,作者: 冰 河. 在JDK中,提供了这样一 ...

  10. Istio(五):使用服务网格Istio进行流量路由

    目录 一.模块概览 二.系统环境 三.简单路由 3.1 简单路由 四.Subset和DestinationRule 4.1 Subset 和 DestinationRule 4.2 Destinati ...