Python实例(六)

如何使用线程池

解决方法:Python3中有线程池的实现。使用标准库中concurrent.futures下的ThreadPoolExecutor,对象的submit和map方法可以用来启动线程池中线程执行任务

from concurrent.futures import ThreadPoolExecutor
executor=ThreadPoolExecutor(3) ##创建一个Executor对象,指定线程池中有几个线程

##使用线程池中线程执行任务
def f(a,b):
    print('f',a,b)
    return a**b

executor.submit(f,2,3) 
##调用线程池中线程执行函数,传入函数,及相应参数
##函数运行结束后,线程归还到线程池,并返回future对象

future.result()##获取线程执行函数的结果

executor.map(f,[2,3,4],[4,5,6]) 
##在多个线程上同时调用函数,参数传入列表
##当线程池中所有线程都在忙碌,再传入一个任务则要等待一个空闲线程才会运行

如何使用多进程

场景:由于python中GIL的存在,再任意时刻只允许一个线程再解释器中运行。因此python的多线程不适合处理cpu密集型的任务。
想要处理cpu密集型任务,可以采用多进程模型
ps:多个进程则有多个GIL锁,一个进程的多个线程只能一个一个执行

解决方法:使用标准库中multiprocessing.Process 它可以启动子进程执行任务
操作接口,进程间通信,进程间同步等,与Threading.Thread类似

from multiprocessing import Process

def f(s):print (s)

Process(target=f,args=('hello',))
p.start() ##启动进程
p.join() #等待进程的结束

x=1
def g():
    global x
    x=5

p=Process(target=f)
p.start()
x
>1 ##可见子进程和主进程是独立的,x是不一样的

##进程间如何进行通信
from multiprocessing import Queue,Pipe
q=Queue()
def f(q):
    print('start')
    print(q.get()) ##获取队列的值
    print('end')

Process(target=f,args=(q,)).start() 
>start
q.put(100)
>100
>end

c1,c2=Pipe() ##创建双向的管道
c1.send('abc') ##由c1端写入的数据要从c2端读取
c2.recv()##同理,由c2端写入的数据要从c1端读取

def f(c):
    c.send(c.recv()*2)

c1,c2=Pipe()
Process(target=f,args=(c2,)).start()
c1.send(55) ##执行了c.recv()*2
c2.recv() ##执行了c.send()
>110

科普:水仙花数(Narcissistic number)也被称为阿姆斯特朗数(Armstrong number),水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身(例如:1^3 + 5^3+ 3^3 = 153)。

##cpu密集型任务:多进程多线程,寻找水仙花数
from threading import Thread
from multiprocessing import Process

def isArmstrong(n): ##判断水仙花数
    a,t=[].n
    while t>0:
        a.append(t%10)
        t /=10
    k=len(a)
    return sum(x**k for x in a)==n
def findArmstrong(a,b): ##在某一范围查找水仙花数
    print(a,b)
    res=[k for k in range(a,b) if isArmstrong(k)]
    print('%s-%s:%s'%(a,b,res)
def findByThread(*argslist): ##使用多线程
    workers=[]
    for args in argslist:
        worker=Thread(target=findArmstrong,args*=args)
        workers.append(worker)
        worker.start()
    for worker in workers:
        worker.join()
def findByProcess(*argslist):
    workers=[]
    for args in argslist:
        worker=Process(target=findArmstrong,args=args)
        workers.append(worker)
        worker.start()
    for worker in workers:
        worker.join()

if __name__=='__main__':
    import time
    start=time.time()
    findByProcess((2000000,2500000),(2500000,300000)) ##进程花费15秒多
    findByThread((2000000,2500000),(2500000,300000))
    ##cpu利用不到100%,线程花费40秒多
    print(time.time()-start)

如何使用函数装饰器

场景:为多个函数统一添加某种功能,不用一一添加相同代码。比如计时统计,记录日志,缓存运算结果等等

解决方案:定义装饰器函数,用它来生成一个在原函数基础添加了新功能的函数,代替原函数

##设计一个装饰器解决重复计算子问题的例子(减少重复计算):
##用缓存记录之前的计算结果,在每一次计算前检查以前的运算是否可以拿来利用

def memo(func):
    cache={}
    def wrap(*args):
        if args not in cache:
            cache[args]=func(*args)
        return cache[args]
    return wrap

##题目一:斐波那契数列:指的是1,1,2,3,5,8,13,21...
##这个数列从第三项开始,每一项都等于前两项之和,求数列第n项

@memo ##等价于fibonacci=memo(fabonacci)
def fibonacci(n):
    if n <= 1:
        return 1
    return fibonacci(n-1)+fibonacci(n-2)

##题目二:一个共有10个台阶的楼梯,从下面追到上面,一次只能迈
##1-3个台阶,并且不能后退,走完这个楼梯共有多少种方法。(回溯法问题)

@memo
def climb(n,step):
    count=0
    if n==0:
        count=1
    elif n>0:
        for step in steps:
            count+=climb(n-step,steps)
    return count

climb(10,(1,2,3))

如何为被装饰的函数保存元数据

在函数对象中保存这一些函数的元数据,例如
f.__name__:函数的名字
f.__doc__:函数文档字符串
f.__moudle__:函数所属模块名
f.__dict__:属性字典
f.__defaults__:默认参数元组

我们在使用装饰器后,再使用上面这些属性访问时,看到的是内部包裹函数的元数据,原来函数的元素据便丢失掉了

解决方法:使用标准库functools中的装饰器wraps装饰内部包裹函数,可以 制定将原函数的某些属性,更新到包裹函数上面

def f():
    '''f function''' ##定义文档字符串
    a=2
    return a*2

##举例    
f.__name__
>'f'
f.__doc__
>'f function'
f.__module__
>'__main__'

def mydecirator(func):
    def wrapper(*args,**kargs):
        '''wrapper function'''
        print('In wrapper')
        func(*args,**kargs)

    return wrapper

## @mydecorator 
def example():
    '''example function'''
    print('In example')

##在没有装饰器的情况下
example.__name__
>'example'
example.__doc__
>'example function'

##在有装饰器的情况下
##example.__name__
##>'wrapper'
##example.__doc__
##>'wrapper function'
##修改后
from functools import updata_wrapper,wraps
def mydecirator(func):
    ##@wraps(func) ##最简单,直接使用装饰器
    def wrapper(*args,**kargs):
        '''wrapper function'''
        print('In wrapper')
        func(*args,**kargs)
    updata_wrapper(wrapper,func,('__name__','__doc__'),('__dict__',))
    ##将原函数的属性更新到包裹函数当中
    ##参数分别是包裹函数,被包裹函数,替换的元数据,合并的元数据
    ##后两项参数的默认值分别为('__module__'__name__','__doc__'),('__dict__')
    return wrapper

@mydecorator 
def example():
    '''example function'''
    print('In example')

example.__name__
>'example'
example.__doc__
>'example function'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值