您的位置:首页 > 编程语言 > Python开发

python 并发编程

2017-09-27 18:55 218 查看

概念

首先我们先了解下关于 并发与并行 的概念,这很容易让人混淆如果不注意的话,甚至会有人认为两者是一样的,统称为大家熟悉的并发编程;
引用下Erlang之父的解释



ConcurrentTwo queues and one coffee machine.
ParallelTwo queues and two coffee machines.
个人理解:
并发:可以理解为多个线程在单核上交替运行,每个线程都会分得一定的CPU时间片;
并行:可以理解为多个线程在多核上同时运行,每个线程都会独享一个CPU;

进程、线程、协程的区别:

进程:

在Python中可以理解为仅只有进程可以称为并发编程,可以充分利用多核,它不像Java和C++,因为会受制于Python的GIL(Global Interpreter Lock)全局解释器锁。

线程:

        Python的多线程在某种程度上讲是比较尴尬的存在,受制于Python的GIL(Global Interpreter Lock)全局解释器锁,阻止Python代码同时在多个处理器核心上运行,因为一个Python解释器在同一时刻只能运行于一个处理器之中。
        1、对于CPU密集型计算, 并不能算真正的并行计算,不能发挥多核的作用;
        2、对于IO 密集型(如爬虫等),由于GIL的原因,虽然在性能上优于单线程,但多线程的切换, 资源的申请释放 成本开销同样也是不可忽略的。

协程:

        在线程与协程之间,个人更偏向于协程,
        1、线程资源开销远大于协程, 线程它有自己的线程空间,在linux下可以理解为一个轻量级进程;
        2、线程的上下文切换可能会引起寄存器和内存间的复制拷贝等;协程在进行切换时,是代码块进行切换(栈跳转),可以更多的利用CPU时间片;

编程样例:




多进程使用

# -*- encoding:utf8 -*-
"""
author: quanbin_zhu
time  : 2017/9/8 18:41
"""
import multiprocessing
#方法一:将要执行的方法作为参数传给Thread的构造方法
def work(id):
time.sleep(1)
print 'the process id is:%s' % id
for i in xrange(3):
p = multiprocessing.Process(target=work, args=(i,))
p.start()

#方法二:从Process继承,并重写run()
class WorkProcess(multiprocessing.Process):
def __init__(self, id):
multiprocessing.Process.__init__(self)
self.id = id

def run(self):
print 'the process id is:%s' % self.id

for i in xrange(3):
p = WorkProcess(i)
p.start()


多线程使用

# -*- encoding:utf8 -*-
"""
author: quanbin_zhu
time  : 2017/9/8 18:46
"""
import threading
import time
#方法一:将要执行的方法作为参数传给Thread的构造方法
def show(id):
time.sleep(1)
print 'the thread id is:%s' % id

for i in xrange(3):
t =threading.Thread(target=show,args=(i,))
t.start()

#方法二:从Thread继承,并重写run()
class MyThread(threading.Thread):
def __init__(self, id):
super(MyThread, self).__init__()
self.id = id
def run(self):
time.sleep(1)
print 'the thread id is:%s' % self.id

for i in xrange(3):
t =MyThread(i)
t.start()


多协程使用

# -*- encoding:utf8 -*-
"""
author: quanbin_zhu
time  : 2017/9/8 18:51
"""
import gevent
from gevent import monkey;monkey.patch_all()
from gevent.pool import Pool
from functools import partial

class Task(gevent.Greenlet):
def __init__(self, id):
super(Task, self).__init__()
self.task_id = id

def _run(self):
for index in xrange(1, 6):
print "task id %s,  output value %s" % (self.task_id, index)
gevent.sleep(0)

def show(id, f, t):
for index in xrange(f, t):
print "task id %s,  output value %s" % (id, index)
gevent.sleep(0)

# 方法调用
def func_dispatch():
func = partial(show, f = 1, t=3)
g1 = gevent.spawn(func, "gevent-01")
g1.join()

# 类调用
def class_dispatch():
tasks = [ Task(i) for i in xrange(0,3)]
map(lambda t: t.start(), tasks)
map(lambda t: t.join(), tasks)

# 类和Pool结合调用
def class_dispatch_with_pool():
tasks = [Task(i) for i in xrange(0, 3)]
pools = Pool(2)
map(lambda t: pools.start(t), tasks)
pools.join()

if __name__ == '__main__':
func_dispatch()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: