个人笔记——Python高级语法

GIL(全局解释器锁)

GIL

例1:单线程死循环

while True:
	pass

在这里插入图片描述
会占用满单核cpu

例2:双线程死循环

import threading

# 子线程死循环
def test():
	while True:
		pass

t1 = threading.Thread(target=test)
t1.start()

# 主线程死循环
while True
	pass

在这里插入图片描述
双核差不多各占用50%CPU

例3:双进程死循环

import multiprocessing

def test():
	while True:
		pass

t1 = multiprocessing.Process(target=test)
t1.start()

while True:
	pass

在这里插入图片描述
双核CPU都被占满

以上例子表明,真正能实现并发肯定是多进程

而多线程实际上在一个时刻真正运行的只有一个线程,其他在等待休息,而GIL就是这个现象的原因
GIL保证多线程程序同一时刻只有一个线程在执行

GIL不是Python语言自带的,而是Python的解释器(cpython)中带有的

GIL的优劣:
GIL不适用于计算密集型,即没有等待时间呢那种,且计算量、操作量极大,无法发挥出多核优势,推荐使用多进程
GIL适用于IO密集型,如网络通信、文件读写等有等待时间的程序,可以再等待过程中运行其他线程

避免GIL的方法

1.使用非cpython的解释器,如用java写的jpython
2.使用其他语言编写,例如可以用c语言编写部分程序,然后再python内调用,如下例
(1)用c语言编写死循环

#include<stdio.h>
void DeadLoop()
{
   
	while(1)
	{
   
		;
	}
}

上方执行完后的文件名未loop.c

(2)在终端将c文件编译成一个动态库的命令(Linux平台下)使其能被python调用

gcc loop.c -shared -o libdead_loop.so

(3)在python中调用上方生成的动态库

from ctypes import *
from threading import Thread

# 加载动态库
lib = cdll.LoadLibrary("./libdead_loop.so")

# 创建一个子进程,让其执行c语言编写的函数,次函数是一个死循环
t = Thread(target = lib.DeadLoop)
t.start()

# 主线程
while True:
	pass

常见面试题

描述Python GIL的概念,以及它对python多线程的影响?编写一个多线程抓取网页的程序,并阐明多线程抓取程序是否可比单线程性能有提升,并解释原因。
答案:
1.Python语言和GIL并没有关系,仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL
2.GIL:全局解释器锁,每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码
3.线程释放GIL锁的情况:在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间到达阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100
4.Python使用多进程是可以利用多核的CPU资源的
5.多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁

深拷贝和浅拷贝

浅拷贝

浅拷贝是对于一个对象的顶层拷贝
例1:先对对象与引用的关系有一定概念

>>a = [11, 22]
>>b = a
>>a = [1, 2]
>>b
>[11, 22]
>>b = a
>>a.append(3)
>>b
>[1, 2, 3]

例2:浅拷贝示例:

>>import copy
>>a = [11, 22]
>>b = [33, 44]
>>c = [a, b]
>>d = copy.copy(c)
>>id(c)
>2689410213320
>>id(d)
>2689410102344
>>id(c[0])
>2689410144008
>>id(d[0])
>2689410144008

上例说明浅拷贝只是对c这一层进行了拷贝(即c、d指向地址不同),内部依旧是原先的指向(即依旧是指向原先a、b的地址)
注1:copy.copy()如果是copy 元组,则会指向同一个地址,因为元组是不可变类型,意味着数据一定不能修改,copy没有意义(前提是元组内的都是指向不可变的数据)
注2:通过列表的切片也能进行copy,如b = a[:], 并且是浅拷贝
例:

import copy
>>a = [11, 22]
>>b = [33, 44]
>>c = (a, b)
>>d = copy.copy(c)
>>e = copy.deepcopy(c)
>>id(c)
>2689410213320
>>id(d)
>2689410213320
>id(e)
>2689410102344
>>a.append(88)
>>c
>([11, 22, 88], [33, 44])
>>d
>([11, 22, 88], [33, 44])
>>e
>([11, 22], [33, 44])

深拷贝

例1:

import copy

>>a = [11, 22]
>>b = a
>>id(a)
>2689406558856
>>id(b)
>2689406558856
>>c = copy.deepcopy(a)
>>id(c)
>2689410144008
>>a.append(33)
>>a
>[11, 22, 33]
>>b
>11, 22, 33]
>>c
>[11, 22]

即通过深拷贝,给c重新指向了一个新的地址,数据和原先的相同

例2:深拷贝说明

>>import copy
>>a = [11, 22]
>>b = [33, 44]
>>c 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值