1 GIL(Global Interpretor Lock,全局解释器锁)

see:

如果其他条件不变,Python程序的执行速度直接与解释器的“速度”相关。不管你怎样优化自己的程序,你的程序的执行速度还是依赖于解释器执行你的程序的效率。

目前来说,多线程执行还是利用多核系统最常用的方式。尽管多线程编程大大好于“顺序”编程,不过即便是仔细的程序员也没法在代码中将并发性做到最好。

对于任何Python程序,不管有多少的处理器,任何时候都总是只有一个线程在执行。

事实上,这个问题被问得如此频繁以至于Python的专家们精心制作了一个标准答案:”不要使用多线程,请使用多进程。“但这个答案比那个问题更加让人困惑。

GIL对诸如当前线程状态和为垃圾回收而用的堆分配对象这样的东西的访问提供着保护。然而,这对Python语言来说没什么特殊的,它需要使用一个GIL。这是该实现的一种典型产物。现在也有其它的Python解释器(和编译器)并不使用GIL。虽然,对于CPython来说,自其出现以来已经有很多不使用GIL的解释器。

不管某一个人对Python的GIL感觉如何,它仍然是Python语言里最困难的技术挑战。想要理解它的实现需要对操作系统设计、多线程编程、C语言、解释器设计和CPython解释器的实现有着非常彻底的理解。单是这些所需准备的就妨碍了很多开发者去更彻底的研究GIL。

2 threading

threading 模块提供比/基于 thread 模块更高层次的接口;如果此模块由于 thread 丢失而无法使用,可以使用 dummy_threading 来代替。

CPython implementation detail: In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.

举例:

import threading, zipfile

class AsyncZip(threading.Thread):
def __init__(self, infile, outfile):
threading.Thread.__init__(self)
self.infile = infile
self.outfile = outfile
def run(self):
f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print 'Finished background zip of: ', self.infile background = AsyncZip('mydata.txt', 'myarchive.zip')
background.start()
print 'The main program continues to run in foreground.' background.join() # Wait for the background task to finish
print 'Main program waited until background was done.'

2.1 创建线程

import threading
import datetime class ThreadClass(threading.Thread):
def run(self):
now = datetime.datetime.now()
print "%s says Hello World at time: %s" % (self.getName(), now) for i in range(2):
t = ThreadClass()
t.start()

2.2 使用线程队列

import Queue
import threading
import urllib2
import time
from BeautifulSoup import BeautifulSoup hosts = ["http://yahoo.com", "http://google.com", "http://amazon.com",
"http://ibm.com", "http://apple.com"] queue = Queue.Queue()
out_queue = Queue.Queue() class ThreadUrl(threading.Thread):
"""Threaded Url Grab"""
def __init__(self, queue, out_queue):
threading.Thread.__init__(self)
self.queue = queue
self.out_queue = out_queue def run(self):
while True:
#grabs host from queue
host = self.queue.get() #grabs urls of hosts and then grabs chunk of webpage
url = urllib2.urlopen(host)
chunk = url.read() #place chunk into out queue
self.out_queue.put(chunk) #signals to queue job is done
self.queue.task_done() class DatamineThread(threading.Thread):
"""Threaded Url Grab"""
def __init__(self, out_queue):
threading.Thread.__init__(self)
self.out_queue = out_queue def run(self):
while True:
#grabs host from queue
chunk = self.out_queue.get() #parse the chunk
soup = BeautifulSoup(chunk)
print soup.findAll(['title']) #signals to queue job is done
self.out_queue.task_done() start = time.time()
def main(): #spawn a pool of threads, and pass them queue instance
for i in range(5):
t = ThreadUrl(queue, out_queue)
t.setDaemon(True)
t.start() #populate queue with data
for host in hosts:
queue.put(host) for i in range(5):
dt = DatamineThread(out_queue)
dt.setDaemon(True)
dt.start() #wait on the queue until everything has been processed
queue.join()
out_queue.join() main()
print "Elapsed Time: %s" % (time.time() - start)

3 dummy_threading(threading的备用方案)

dummy_threading 模块提供完全复制了threading模块的接口,如果无法使用thread,则可以用这个模块替代.

使用方法:

try:
import threading as _threading
except ImportError:
import dummy_threading as _threading

4 thread

在Python3中叫 _thread,应该尽量使用 threading 模块替代。

5 dummy_thread(thead的备用方案)

dummy_thread 模块提供完全复制了thread模块的接口,如果无法使用thread,则可以用这个模块替代.

在Python3中叫 _dummy_thread, 使用方法:

try:
import thread as _thread
except ImportError:
import dummy_thread as _thread

最好使用 dummy_threading 来代替.

6 multiprocessing(基于thread接口的多进程)

see:

使用 multiprocessing 模块创建子进程而不是线程来克服GIL引起的问题.

举例:

from multiprocessing import Pool

def f(x):
return x*x if __name__ == '__main__':
p = Pool(5)
print(p.map(f, [1, 2, 3]))

6.1 Process类

创建进程是使用Process类:

from multiprocessing import Process

def f(name):
print 'hello', name if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()

6.2 进程间通信

Queue 方式:

from multiprocessing import Process, Queue

def f(q):
q.put([42, None, 'hello']) if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print q.get() # prints "[42, None, 'hello']"
p.join()

Pipe 方式:

from multiprocessing import Process, Pipe

def f(conn):
conn.send([42, None, 'hello'])
conn.close() if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print parent_conn.recv() # prints "[42, None, 'hello']"

6.3 同步

添加锁:

from multiprocessing import Process, Lock

def f(l, i):
l.acquire()
print 'hello world', i
l.release() if __name__ == '__main__':
lock = Lock() for num in range(10):
Process(target=f, args=(lock, num)).start()

6.4 共享状态

应该尽量避免共享状态.

共享内存方式:

from multiprocessing import Process, Value, Array

def f(n, a):
n.value = 3.1415927
for i in range(len(a)):
a[i] = -a[i] if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10)) p = Process(target=f, args=(num, arr))
p.start()
p.join() print num.value
print arr[:]

Server进程方式:

from multiprocessing import Process, Manager

def f(d, l):
d[1] = '1'
d['2'] = 2
d[0.25] = None
l.reverse() if __name__ == '__main__':
manager = Manager() d = manager.dict()
l = manager.list(range(10)) p = Process(target=f, args=(d, l))
p.start()
p.join() print d
print l

第二种方式支持更多的数据类型,如list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value ,Array.

6.5 Pool类

通过Pool类可以建立进程池:

from multiprocessing import Pool

def f(x):
return x*x if __name__ == '__main__':
pool = Pool(processes=4) # start 4 worker processes
result = pool.apply_async(f, [10]) # evaluate "f(10)" asynchronously
print result.get(timeout=1) # prints "100" unless your computer is *very* slow
print pool.map(f, range(10)) # prints "[0, 1, 4,..., 81]"

7 multiprocessing.dummy

在官方文档只有一句话:

multiprocessing.dummy replicates the API of multiprocessing but is no more than a wrapper around the threading module.

  • multiprocessing.dummy 是 multiprocessing 模块的完整克隆,唯一的不同在于 multiprocessing 作用于进程,而 dummy 模块作用于线程;
  • 可以针对 IO 密集型任务和 CPU 密集型任务来选择不同的库. IO 密集型任务选择multiprocessing.dummy,CPU 密集型任务选择multiprocessing.

举例:

import urllib2
from multiprocessing.dummy import Pool as ThreadPool urls = [
'http://www.python.org',
'http://www.python.org/about/',
'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
'http://www.python.org/doc/',
'http://www.python.org/download/',
'http://www.python.org/getit/',
'http://www.python.org/community/',
'https://wiki.python.org/moin/',
'http://planet.python.org/',
'https://wiki.python.org/moin/LocalUserGroups',
'http://www.python.org/psf/',
'http://docs.python.org/devguide/',
'http://www.python.org/community/awards/'
# etc..
] # Make the Pool of workers
pool = ThreadPool(4)
# Open the urls in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)
#close the pool and wait for the work to finish
pool.close()
pool.join() results = []
for url in urls:
result = urllib2.urlopen(url)
results.append(result)

8 后记

  • 如果选择多线程,则应该尽量使用 threading 模块,同时注意GIL的影响
  • 如果多线程没有必要,则使用多进程模块 multiprocessing ,此模块也通过 multiprocessing.dummy 支持多线程.
  • 分析具体任务是I/O密集型,还是CPU密集型

【转】Python中的GIL、多进程和多线程的更多相关文章

  1. 线程安全及Python中的GIL

    线程安全及Python中的GIL 本博客所有内容采用 Creative Commons Licenses 许可使用. 引用本内容时,请保留 朱涛, 出处 ,并且 非商业 . 点击 订阅 来订阅本博客. ...

  2. 聊聊Python中的GIL

    对于广大写Python的人来说,GIL(Global Interpreter Lock, 全局解释器锁)肯定不陌生,但未必清楚GIL的历史和全貌是怎样的,今天我们就来梳理一下GIL. 1. 什么是GI ...

  3. 深入理解Python中的GIL(全局解释器锁)

    深入理解Python中的GIL(全局解释器锁) Python是门古老的语言,要想了解这门语言的多线程和多进程以及协程,以及明白什么时候应该用多线程,什么时候应该使用多进程或协程,我们不得不谈到的一个东 ...

  4. Python中的GIL

    •start 线程准备就绪,等待CPU调度 •setName 为线程设置名称 •getName 获取线程名称 •setDaemon 设置为后台线程或前台线程(默认) 如果是后台线程,主线程执行过程中, ...

  5. 为什么在python中推荐使用多进程而不是多线程(转载)

    最近在看Python的多线程,经常我们会听到老手说:"Python下多线程是鸡肋,推荐使用多进程!",但是为什么这么说呢? 要知其然,更要知其所以然.所以有了下面的深入研究: GI ...

  6. python中的GIL详解

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

  7. python并发编程之多进程、多线程、异步、协程、通信队列Queue和池Pool的实现和应用

    什么是多任务? 简单地说,就是操作系统可以同时运行多个任务.实现多任务有多种方式,线程.进程.协程. 并行和并发的区别? 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任 ...

  8. python 中的GIL (全局解释器锁)详解

    1.GIL是什么? GIL全称Global Interpreter Lock,即全局解释器锁. 作用就是,限制多线程同时执行,保证同一时间内只有一个线程在执行. GIL并不是Python的特性,它是在 ...

  9. Python - 并发编程,多进程,多线程

    传送门 https://blog.csdn.net/jackfrued/article/details/79717727 在此基础上实践和改编某些点 1. 并发编程 实现让程序同时执行多个任务也就是常 ...

  10. Python中的GIL锁

    在Python中,可以通过多进程.多线程和多协程来实现多任务. 在多线程的实现过程中,为了避免出现资源竞争问题,可以使用互斥锁来使线程同步(按顺序)执行. 但是,其实Python的CPython(C语 ...

随机推荐

  1. Objective-C在windows开发环境的搭建

    转自 http://www.hdj.me/objective-c-in-windows 安装GNUstep GNUstep Windows Installer提供了Windows平台下的Objecti ...

  2. 【Vegas原创】EXCEL光标所在的行自动变色

      方法: 1,excel中,按Alt+F11,打开VBA编辑界面,双击需要改的工作表名称,将下面代码粘贴到右边框中,即可. 2,代码: Private Sub Worksheet_Selection ...

  3. [转]java byte 数据类型(基础)

    package com.suypower.chengyu.test; public class ByteTest { /** * byte 8 bits -128 - + 127 * 1 bit = ...

  4. python排序算法的实现-快速排序

    1. 算法描述: 1.先从数列中取出一个数作为基准数. 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边. 3.再对左右区间重复第二步,直到各区间只有一个数. 2.pyth ...

  5. ubuntu 12.04 安装Docker 实战

    2016-3-8 从网络服务商那里申请到一台Ubuntu测试服务器,用来测试安装Docker环境. 注:本人初学Docker,对Linux命令也仅是稍稍了解,如有错误,烦请告知. 查看系统相关信息 可 ...

  6. Folder Recursion with C#

    by Richard Carr, published at http://www.blackwasp.co.uk/FolderRecursion.aspx Some applications must ...

  7. <《巴菲特之道 (第三版)》>读书笔记

    以便宜的价格买入长期绩优的股票 他把对公司的投资看做是拥有公司的一部分股权,看重的是公司的长期经济价值 别人越是草率,我们越要加倍慎重 如果你发现自己已经在陷阱中,最重要的是想办法让自己不要再往下陷 ...

  8. Django 源码小剖: Django 对象关系映射(ORM)

    引 从前面已经知道, 一个 request 的到来和一个对应 response 的返回的流程, 数据处理和数据库离不开. 我们也经常在 views.py 的函数定义中与数据库打交道. django O ...

  9. Mac mongodb 配置安装

    简单总结就几条,比较简单配置mongodb. 1,首先下载安装包:百度云下载地址 2,下载之后解压到自己常放的工作目录下,然后开始配置一下你的Mac环境 vim ~/.bash_profile 添加m ...

  10. 【Math】余弦相似度 和 Pearson相关系数

    http://cucmakeit.github.io/2014/11/13/%E4%BF%AE%E6%AD%A3%E4%BD%99%E5%BC%A6%E7%9B%B8%E4%BC%BC%E5%BA%A ...