python学习笔记-生成器,迭代器,协程定义

生成器

知识点:生成器就是通过封装的算法进行边循环边计算的机制,通过next()方法可以每次取一个计算的值,也就是yield b 这个b是多少(x = next(generator) 这个x就是取到的b)。x = yield,那么x 就是用于接收外部发来的值(generator.send(5),那么x就是5)。

通过列表生成式我们可以取得想要的值,但是如果我们创建了一个包含了百万个值的列表,而只要取前面的几个值,显然这造成了内存和时间的浪费。此时,如果我们能用某种方法来把我们想要的值循环计算出来,那么这无疑解决了上面的问题。这种通过某种算法进行边循环边计算的功能,称作生成器。
创建一个生成器的方法有

1.直接把列表推导式的[] 变为 ()

>>> g1 = (x for x in range(5))
>>> next(g1)    # 通过 next(g1) 或者 g1.send(None) 或者 g1,__next__() 启动生成器  (next(g1) == g1.send(None))
0
>>> next(g1)    # 再通过next(g1) g1.send(None)  就可以取得下一个值或者 g1.send(5)
1
>>> g1.send(4)
2
>>> list(g1)    # 一次性取出剩下的值
[3, 4]
>>> next(g1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

当然,重新创建一个生成器g1,我们可以直接用for循环进行迭代取值

>>> g1 = (x for x in range(5))
>>> for i in g1:
...     print(i)
...
0
1
2
3
4

2.当需要计算一些复杂的值时(比如计算斐波那契数),用列表推导式无法实现。 这时候我们要用函数实现。

def fib(max):
    n, a, b = 0, 0, 1
    print('aaa')
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
	print('a')
>>>fib(6)
aaa
1
1
2
3
5
8
a

我们说过生成器保存的是算法,如果这个算法封装在函数里,那我们如何将这个函数变成生成器呢? 将yield放在循环中就可以实现。yield可以接收外部发送的值(消费者生产者模式就是利用这个特性),还可以用于生成函数内部迭代的值
(1) yield用于生成函数内部迭代的值

def fib(max):
    n, a, b = 0, 0, 1
    print('aaa')
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
	print('a')

>>> g = fib(5)
>>> for i in g:
...     print(i)
...
aaa
1
1
2
3
5
a

函数的生成器也可以用next启动,取值
>>> g = fib(5)
>>> next(g)     # 解析:启动生成器,程序执行到yield处等待,接下来yield就可以用于接收值(下面会有生产者消费者模式)。以后每次next都会循环一次while语句
aaa
1
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> g.send(5)
5

(2)yield可以接收外部发送的值(生产者消费者模式)

def consumer(name):
	weikou = 0
	while weikou < 10:
		egg = yield
		print("%s 在吃 egg [%s]" % (name,egg))
		weikou += 1

c = consumer('Tom')
next(c)    # 此处等待接收
c.send(1)    # Tom 在吃 egg [1]
c.send(2)    # Tom 在吃 egg [2]
 

def producer():
	c1 = consumer("Tom")
	c2 = consumer("John")
	c1.__next__()
	c2.send(None)
	for i in range(3):
		c1.send(i)
		c2.send(i)

p = producer()
out-------------
Tom 在吃 egg [1]
Tom 在吃 egg [2]
Tom 在吃 egg [0]
John 在吃 egg [0]
Tom 在吃 egg [1]
John 在吃 egg [1]
Tom 在吃 egg [2]
John 在吃 egg [2]

通过队列的生产者消费者模式 https://blog.csdn.net/qq_34964399/article/details/78718279
上面这段代码是最简单的单线程下的并行的例子,也即协程,能同时进行多个任务。例子中就是2个消费者在同时吃包子,如果不用生成器的话,那么就需要等到一个人吃完了包子,另一个人再吃。

迭代器

用于for循环的数据类型有2类。
1.集合数据类型 list,dict,tuple,set,str…
2.generator。包括生成器和带yield的generator function

只要是可以用for循环,那他就是可迭代对象(Iterable)。

>>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> isinstance([1,2,3],Iterable)
True
>>> isinstance((),Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance((x for x in range(10)),Iterable)
True

而像生成器这种还能用next()不断调用取值的就是迭代器。而集合数据类型的就不是迭代器

>>> from collections import Iterator
>>> isinstance([],Iterator)
False
>>> isinstance((x for x in range(10)),Iterator)
True

如果想把集合数据类型转为迭代器,可以用iter方法进行转换

>>> isinstance(iter([]),Iterator)
True

其实python的for循环本质上也是用next()调用的。

for i in [1,2,3,4,5]:
	print(i)

#等价于

it = iter([1,2,3,4,5])

while True:	
	try:
		x = next(it)
		print(x)
	except StopIteration as e:
		break

协程定义
1.必须在只有一个单线程里实现并发
2.修改共享数据不需加锁
3.用户程序里自己保存多个控制流的上下文栈
4.一个协程遇到IO操作自动切换到其它协程

根据协程定义,上面的写的生产者消费者模型并不属于严格意义上的协程,因为并没有进行IO操作

mysql协程

协程读取数据

我们在定义函数的时候在前面加上async修饰,在耗时任务那行代码使用await修饰,这时候调用函数,它就会返回一个协程(coroutine)对象,然后调用asyncio.run()把协程对象丢进去就能执行了

def get_tables_lst(schema):
    if schema == 'gp20i17mp_lf':
        tables = 'l9_drt_paa_entity,l9_drt_paa_run_detail,l9_drt_paa_insurance_contract_group,l9_drt_paa_insurance_contract_group_detl,l9_drt_paa_insurance_contract_group_assoc,l9_drt_paa_insurance_contract_portfolio,l9_drt_paa_calc_input_measure'
    elif schema == 'gp20i17mp_hf':
        tables = 'l9_drt_paa_entity,l9_drt_paa_run_detail,l9_drt_paa_insurance_contract_group,l9_drt_paa_insurance_contract_group_detl,l9_drt_paa_insurance_contract_group_assoc,l9_drt_paa_insurance_contract_portfolio,l9_drt_paa_calc_input_measure'
    return tables.split(",")
tables_lst = get_tables_lst(schema)
class DBPool(object):
    def __init__(self):
        # self.coon = None
        self.pool = None
        # self.lg = lg

    async def initpool(self):
        try:
            # self.lg.logger.debug("即将连接postgresql")
            print("即将连接postgresql")
            self.pool = await asyncpg.create_pool(
                min_size=5,
                max_size=10,
                user='read',
                host='*****',
                port=3432,
                password="****",
                database="ifrs17db")
        except Exception:
            pass


    async def quety_to_pd(self, query, table_name):
        conn = await self.pool.acquire()
        try:
            result = await conn.fetch(query)
            print("table_name: " , table_name, " columns: ", len([x for x in result[0].keys()]) ," rows: ", len(result) + 1)

        except Exception as e:
        	print("error", e)
        finally:
            # 释放掉conn,将连接放回到连接池中
            await self.pool.release(conn)



db = DBPool()
loop = asyncio.get_event_loop()
tasks = [db.initpool()]
loop.run_until_complete(asyncio.wait(tasks))

tasks=[]
for table in tables_lst: # 
    sql = "SELECT * FROM {}.{}".format(schema, table)
    tasks.append(db.quety_to_pd(sql,table))

loop.run_until_complete(asyncio.wait(tasks))
![在这里插入图片描述](https://img-blog.csdnimg.cn/bdba2c0386794ebe94cb653042c05291.png)
 


在这里插入代码片

import time,asyncio
# await: 当该任务被挂起后,CPU会⾃动切换到其他任务中

async def func1():
    print("func1, start")
    await asyncio.sleep(3)
    print("func1, end")

async def func2():
    print("func2, start")
    await asyncio.sleep(4)
    print("func2, end")

async def func3():
    print("func3, start")
    await asyncio.sleep(2)
    print("func3, end")

# if __name__ == '__main__':
#     start = time.time()
#     tasks = [ # 协程任务列表
#         func1(), # 创建协程任务
#         func2(),
#         func3()
#     ]
#     lop = asyncio.get_event_loop()
#     lop.run_until_complete(func1())
      
#     # 我要执⾏这个协程任务列表中的所有任务
#     lop.run_until_complete(asyncio.wait(tasks))
#     # 我要执⾏这个协程任务列表中的所有任务
#     print(time.time() - start)
#     lop.close()

'''
    func1, start
    func1, end  --会先等func1执行完
    func1, start
    func2, start
    func3, start
    func3, end
    func1, end
    func2, end
    7.0143232345581055

'''


# 上⾯的程序还可以写成这样
async def main():
    print("start")
    tasks = [
        func1(),
        func2(),
        func3()
    ]
# ⼀次性把所有任务都执⾏
    await asyncio.wait([func1()])  # 也会等这个运行完
    done, pedding = await asyncio.wait(tasks)
    print("end")
if __name__ == '__main__':
    start = time.time()
    asyncio.run(main())
    print(time.time() - start)

'''
start
func1, start
func1, end
func1, start
func3, start
func2, start
func3, end
func1, end
func2, end
end
7.014348268508911
[Finished in 7.2s]
'''

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值