> Python 多线程因为GIL的存在,导致其速度比单线程还要慢。但是近期我发现了一个相当好用的库,这个库只需要增加一个修饰符就可以使原生的python多线程实现真正意义上的并发。本文将和大家一起回顾下GIL对于多线程的影响,以及了解通过一个修饰符就可以实现和C++一样的多线程。

## GIL的定义

GIL的全称是global interpreter lock,官方的定义如下:

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.)

从官方的解释来看,这个全局锁是用来防止多线程同时执行底层计算代码的。之所以这么做,是因为底层库Cpython,在内存管理这块是线程不安全的。

## GIL有好处吗

对GIL的第一印象是这东西限制了多线程并发,对python而言是个弊大于利的存在。但是从stackoverflow上的讨论来看,这个存在还是相当有必要的。

- 增加了单线程的运行速度

- 可以更方便地整合一些线程不安全的C语言库到python里面去

首先单线程的运行速度更快了,因为有这个全局锁的存在,在执行单线程计算的时候不需要再额外增加锁,减少了不必要的开支。第二个则是可以更好地整合用C语言所写的python库。现在其实挺多用C语言写好底层计算然后封装提供python接口的,比如数据处理领域的pandas库,人工智能领域的计算框架Tensorflow或者pytorch,他们的底层计算都是用C语言写的。由于这个全局锁的存在,我们可以更方便(安全)地把这些C语言的计算库整合成一个python包,对外提供python接口。

## GIL对性能的影响大吗

对于需要做大量计算的任务而言,影响是相当大的。我们先来看一段单线程代码:

```python

class A(object):

def run(self):

ans = 0

for i in range(100000000):

ans += i

a = A()

for _ in range(5):

a.run()

```

以上这段代码是跑5次计算,每次计算是从1累加到1千万,跑这段代码需要17.46s。

紧接着,我们用python的多线程库来实现一个多线程计算:

```python

import threading

class A(object):

def run(self):

ans = 0

for i in range(100000000):

ans += i

threads = []

for _ in range(5):

a = A()

th = threading.Thread(target=a.run)

th.start()

threads.append(th)

for th in threads:

th.join()

```

这里我们启动了5个线程同时计算,然后我们又测试下时间: **41.35**秒!!!这个时候GIL的问题就体现出来了,我们通过多线程来实现并发,结果比单线程慢了2倍多。

### 一个神奇的修饰符

话不多说,我们先来看下代码。以下这段代码和上面的多线程代码几乎一样。但是我们要注意到,在类A的定义上面,我们增加了一个修饰符*@parl.remote_class*。

```python

import threading

import parl

@parl.remote_class

class A(object):

def run(self):

ans = 0

for i in range(100000000):

ans += i

threads = []

parl.connect("localhost:6006")

for _ in range(5):

a = A()

th = threading.Thread(target=a.run)

th.start()

threads.append(th)

for th in threads:

th.join()

```

现在我们来看下计算时间:**3.74秒**!!!相比于单线程的17.46s,这里只用了接近1/5的时间(因为我们开了5个线程)。这里是我觉得比较神奇的地方,并没有做太多的改动,只是在我的单线程类上面增加了一个修饰符,然后用原生的python多线程继续跑代码就变得相当快了。

### 完整的使用说明:

1. 安装这个库:

```shell

pip install --upgrade git+https://github.com/PaddlePaddle/PARL.git

```

2. 在本地通过命令启动一个并发服务(只需要启动一次)

```shell

xparl start --port 6006

```

3. 写代码的时候通过修饰符修饰你要并发的类@parl.remote。

这里需要注意的是只有经过这个修饰符修饰的类才可以实现并发。

4. 在代码最开始的时候通过parl.connect('localhost:6006')来初始化这个包。

最后贴下这个库的使用文档:

https://parl.readthedocs.io/en/latest/parallel_training/setup.html

源码在这里:

https://github.com/PaddlePaddle/PARL/tree/develop/parl/remote

后续会继续研究源码,看下是怎么做到一个修饰符就能加速的。大家如果读过了源码可以一起讨论下:)

c语言多线程转python多线程,真正的python 多线程!一个修饰符让你的多线程和C语言一样快...相关推荐

  1. c语言编程改变旅馆价格,模拟旅馆管理系统的一个功能——床位的分配与回收(c语言编程)...

    模拟旅馆管理系统的一个功能--床位的分配与回收 题目:模拟旅馆管理系统的一个功能--床位的分配与回收 ⒈问题描述: 某旅馆有n个等级的房间,第I等级有 个房间,每个等级有个床位(1≤I≤n).试模拟旅 ...

  2. [python 进阶] 9. 符合Python风格的对象

    文章目录 9.1 对象表示形式 9.2 再谈向量类 9.3 备选构造方法 9.4 classmethod与staticmethod 9.5 格式化显示 9.6 可散列的Vector2d 什么是可散列的 ...

  3. python中@修饰符用法

    @修饰符  '@'符号用作函数修饰符是python2.4新增加的功能,修饰符必须出现在函数定义前一行,不允许和函数定义在同一行.也就是说@A def f(): 是非法的. 只可以在模块或类定义层内对函 ...

  4. python @修饰符_Python基础(面向对象之类成员与修饰符)

    本篇将介绍Python 类的成员.类成员修饰符.类的特殊成员. 类的成员可以分为三大类:字段.方法.属性 1.字段: 也可理解为变量,分为: 普通字段:保存在对象中,访问时通过"对象.字段名 ...

  5. PHP从零开始--字段修饰符数据操作SQL语言

    文章目录 一. 字段修饰符 1.1主键 1.2自动增长 1.3非空 1.4默认值 1.5外键 二. 对数据的操作 2.1增加数据 2.2删除数据 2.3更新数据 2.4查询数据 2.4.1查询所有的数 ...

  6. Python修饰符--函数修饰符 “@”

    Python函数修饰符,"@",与其说是修饰函数倒不如说是引用.调用它修饰的函数. 举个栗子,下面的一段代码,里面两个函数,没有被调用,也会有输出结果: def test(f):p ...

  7. 视频教程-Python数据分析与爬虫-Python

    Python数据分析与爬虫 10年一线开发及项目管理经验,6年以上大数据项目架构.实施.开发与运维经验,骨灰级大数据玩家,对Hadoop.Storm.Spark.Flink.Kylin.Druid等大 ...

  8. python豆瓣电影需研究的问题_python爬虫获取豆瓣电影——多线程问题

    25 May 2015 GIL全称Global Interpreter Lock(全局解释器锁),它是在实现Python解析器(CPython)时所引入的一个概念.但是它并不是Python的特性.Py ...

  9. 【python第三方库】python多线程编程---threading库

    文章目录 一.python多线程 1. GIL 二.threading库使用介绍 1. 创建多线程 2. 线程合并 3. 线程同步与互斥锁Lock 4. 死锁与可重入锁(递归锁)RLock 5. 守护 ...

最新文章

  1. 介绍一个.Net资源站点
  2. 这几个公众号带你看看BAT的工作情况
  3. 阿里rocketmq与自建rocketmq
  4. python读取配置文件获取所有键值对_Python读取properties配置文件操作示例
  5. 【转】20个Java 代码生成器
  6. matlab ifft频率分辨率,matlab中关于FFT的使用(理解频率分辨率、补零问题)
  7. sublime text3 boxy主题 (本地 压缩包 安装)
  8. virsh、qemu-img基本管理操作
  9. 职场人必看:提高工作效率的6大法则
  10. (一)OSG初学者入门基础教程
  11. 使用A*算法求最短路径
  12. pytorch之torch.gather方法
  13. vivado时序约束
  14. 接招吧,最强“高并发”系统设计 46 连问,分分钟秒杀一众面试者
  15. S1000D数据模块类型中英文对照
  16. 猪圈密码(Pigpen)
  17. 公安大数据与图侦应用结合现状分析
  18. 设计师必备取色技巧!教你在PS里通过照片创建色板
  19. 山东高新技术企业申报当年下证的知识产权能用吗?
  20. json的dump和dumps的区别

热门文章

  1. 做ML项目,任务繁多琐碎怎么办?这份自查清单帮你理清思路
  2. 带你少走弯路:五篇文章学完吴恩达机器学习
  3. 打家劫舍(不偷相邻)
  4. Linux之软件安装 apt-get
  5. Numpy的介绍和优势
  6. Linux之查看目录命令
  7. Node2Vec:万物皆可Embedding
  8. 如何通俗的理解面向对象编程
  9. 第十八篇:Question Answering问答系统
  10. 栈与队列3——用递归和栈操作逆序一个栈