(1)理解IO密集型(阻塞)程序
IO密集型(阻塞)程序是指在执行过程中主要涉及输入/输出(IO)操作,并且这些IO操作会导致程序阻塞等待的类型。在这种类型的程序中,CPU的利用率相对较低,因为大部分时间都花费在等待IO操作完成上。
常见的IO操作包括从磁盘读取文件、网络请求、数据库查询等。当程序执行这些IO操作时,通常会发起一个请求,然后等待操作完成并返回结果。在等待的期间,程序会被阻塞,暂时停止执行,直到IO操作完成。
IO密集型(阻塞)程序的特点包括:
-
高度依赖外部资源:程序的执行主要涉及与外部资源的交互,如读写文件、网络通信等。
-
阻塞等待:在执行IO操作时,程序会暂停执行并等待IO操作完成。
-
低CPU利用率:由于大部分时间花费在等待IO操作上,CPU的利用率相对较低。
在编写IO密集型(阻塞)程序时,需要注意合理利用异步编程、多线程或多进程等技术,以提高程序的性能和效率。异步编程可以通过非阻塞IO操作和事件驱动机制来实现并发执行,以避免程序被阻塞。多线程或多进程可以充分利用多核CPU的优势,使得在一个线程或进程等待IO操作时,其他线程或进程可以继续执行,从而提高整体的吞吐量。
需要注意的是,IO密集型(阻塞)程序的性能瓶颈主要在于IO操作本身,而不是CPU的计算能力。因此,在优化IO密集型程序时,重点应该放在减少IO操作的数量、提高IO操作的效率,以及合理利用异步和并发编程技术来提高程序的并发性和响应性。
(2)yield在python中的意义
在Python中,yield
是一个关键字,用于定义生成器函数。生成器函数是一种特殊类型的函数,它可以在执行过程中产生多个值,而不是一次性返回所有结果。
当一个函数中包含yield
语句时,该函数就成为一个生成器函数。生成器函数在被调用时,并不会立即执行函数体内的代码,而是返回一个生成器对象。通过调用生成器对象的__next__()
方法(或使用next()
函数),可以逐个获取生成器函数中yield
语句产生的值。
每次调用生成器对象的__next__()
方法时,生成器函数会从上次yield
语句停止的地方继续执行,直到再次遇到下一个yield
语句,然后将yield
后面的表达式作为结果返回。这样,生成器函数可以在每次迭代中产生一个值,并在下一次迭代时从上次停止的地方继续执行
def my_generator():
yield 1
yield 2
yield 3
# 创建生成器对象
gen = my_generator()
# 通过迭代获取生成器函数产生的值
print(next(gen)) # 输出:1
print(next(gen)) # 输出:2
print(next(gen)) # 输出:3
需要注意的是,生成器函数在每次调用yield
语句后会暂停执行,并保留当前的状态。因此,生成器对象是一种惰性求值的方式,只在需要时才会产生值,可以节省内存和计算资源。
除了使用next()
函数来迭代生成器对象,还可以使用for
循环来遍历生成器函数产生的值。生成器函数还可以接收参数,并根据参数的不同产生不同的值序列。这使得生成器函数非常灵活和高效,特别适合处理大型数据集或需要逐步产生结果的场景。
yield from
语法用于在生成器函数中委托另一个可迭代对象的迭代过程。它提供了一种简洁的方式来将子生成器的值传递给外层生成器。
yield from 可迭代对象
(3)生成器(Generator)和迭代器(Iterator)
生成器是一种特殊类型的迭代器,它是通过生成器函数或生成器表达式创建的。生成器函数使用yield
语句来产生值序列,而生成器表达式使用类似于列表推导式的语法来生成值序列。生成器对象可以通过迭代来逐个获取值,而不需要一次性将所有值加载到内存中。
迭代器是一种可以用于遍历可迭代对象的对象。它实现了__iter__()
和__next__()
方法,可以通过调用__next__()
方法来逐个获取元素。迭代器对象可以使用iter()
函数来创建,并且在迭代过程中可以记录状态,以便下次迭代时继续返回下一个元素。
以下是生成器和迭代器的一些区别:
-
语法:生成器可以使用生成器函数或生成器表达式来创建,而迭代器需要手动实现
__iter__()
和__next__()
方法。 -
状态记录:生成器函数在
yield
语句的位置暂停执行并保留状态,可以从上次停止的地方继续执行。迭代器通过__next__()
方法来记录状态,以便在下次调用时返回下一个元素。 -
内存占用:生成器一次只生成一个值,并且不需要将所有值加载到内存中,因此在处理大型数据集时更节省内存。迭代器可以逐个获取元素,也不需要将所有元素加载到内存中。
-
可复用性:生成器函数可以被多次调用以生成多个生成器对象,每个对象都可以独立地迭代。迭代器在遍历完所有元素后通常需要重新创建,因为它们记录了状态信息。
-
实现复杂性:生成器相对于手动实现迭代器来说更简单,因为它们使用
yield
语句和生成器函数/表达式的语法。手动实现迭代器需要编写__iter__()
和__next__()
方法,并管理状态和迭代逻辑。
(4)python内置迭代器
Python内置函数中有一些返回迭代器的函数。这些函数可以直接用于迭代操作,而不需要显式地创建和管理迭代器对象。以下是一些常用的内置函数,它们返回的是迭代器:
-
iter(iterable)
:返回一个迭代器对象,用于迭代可迭代对象。如果已经是迭代器对象,则直接返回自身。 -
range(start, stop, step)
:返回一个表示指定范围的迭代器对象。可以用于生成一系列连续的整数。 -
map(function, iterable)
:返回一个将函数应用于可迭代对象的每个元素的迭代器对象。函数可以是预定义的函数或匿名函数。 -
filter(function, iterable)
:返回一个根据指定函数筛选可迭代对象的元素的迭代器对象。函数返回True
的元素将被保留。 -
zip(*iterables)
:返回一个将多个可迭代对象中的对应元素打包成元组的迭代器对象。返回的迭代器的长度由最短的可迭代对象决定。 -
enumerate(iterable, start=0)
:返回一个迭代器对象,该对象生成一个元组序列,包含可迭代对象中的索引和对应的元素。 -
sorted(iterable, key=None, reverse=False)
:返回一个将可迭代对象进行排序后的迭代器对象。可以通过key
参数指定排序的方式,以及使用reverse
参数来控制排序顺序。 -
reversed(seq)
:返回一个反向迭代的迭代器对象,用于反向遍历序列。
这些内置函数提供了方便的方式来处理迭代操作,而不需要显式地编写迭代器类或手动管理迭代器对象。通过使用这些函数,可以更简洁地进行迭代和处理可迭代对象的元素。
注:iterable 表示可迭代对象,例如列表、元组和集合等,
(5)可迭代对象和迭代器的区别
可迭代对象是指实现了__iter__()
方法的对象,它可以用于迭代操作,例如在for
循环中遍历元素。列表是一种常见的可迭代对象,可以通过索引访问元素、切片操作等。当我们使用for
循环来遍历列表时,实际上是通过内部的迭代器来逐个获取列表中的元素。
迭代器是一种特殊的可迭代对象,它实现了__iter__()
和__next__()
方法。迭代器可以逐个返回元素,并且在迭代过程中可以维护状态。相比之下,列表不是迭代器,因为它没有实现__next__()
方法,不能逐个返回元素。