你可以使用
map()
和一个生成器一起使用,但它只会尝试映射生成器对象本身,而不会尝试进入生成器中。
一种可能的方法是让生成器按照你想要的方式循环,并让函数对这些对象进行操作。这样做的附加优势是更清晰地将循环与计算分离。因此,类似以下代码应该可行:
from concurrent.futures import ThreadPoolExecutor
import os
def read_samples(samples):
for sample in samples:
with open(os.path.join('samples', sample)) as fff:
for _ in range(10):
yield fff
def main():
with ThreadPoolExecutor(10) as exc:
files = os.listdir('samples')
files = list(exc.map(lambda x: str(x.read()), read_samples(files)))
print(str(len(files)), end="\r")
if __name__=="__main__":
main()
另一种方法是嵌套一个额外的 map
调用来消耗生成器:
from concurrent.futures import ThreadPoolExecutor
import os
def read_samples(samples):
for sample in samples:
with open(os.path.join('samples', sample)) as fff:
for _ in range(10):
yield fff
def main():
with ThreadPoolExecutor(10) as exc:
files = os.listdir('samples')
files = exc.map(list, exc.map(lambda x: str(x.read())), read_samples(files))
files = [f for fs in files for f in fs]
print(str(len(files)), end="\r")
if __name__=="__main__":
main()
一个更加简化的示例
为了提供更具有可重复性的示例,您可以编写一个更加简化的示例来展示代码的特性(不依赖于系统中留下的文件):
from concurrent.futures import ThreadPoolExecutor
def foo(n):
for i in range(n):
yield i
with ThreadPoolExecutor(10) as exc:
x = list(exc.map(foo, range(k)))
print(x)
# [<generator object foo at 0x7f1a853d4518>, <generator object foo at 0x7f1a852e9990>, <generator object foo at 0x7f1a852e9db0>, <generator object foo at 0x7f1a852e9a40>, <generator object foo at 0x7f1a852e9830>, <generator object foo at 0x7f1a852e98e0>, <generator object foo at 0x7f1a852e9fc0>, <generator object foo at 0x7f1a852e9e60>]
from concurrent.futures import ThreadPoolExecutor
def foos(ns):
for n in range(ns):
for i in range(n):
yield i
with ThreadPoolExecutor(10) as exc:
k = 8
x = list(exc.map(lambda x: x ** 2, foos(k)))
print(x)
from concurrent.futures import ThreadPoolExecutor
def foo(n):
for i in range(n):
yield i ** 2
with ThreadPoolExecutor(10) as exc:
k = 8
x = exc.map(list, exc.map(foo, range(k)))
print([z for y in x for z in y])
map
中使用生成器(“yield
函数”)是可能的,但正如您所观察到的那样,这只会实例化该生成器。为什么read_sample
不直接生成列表呢?您使用生成器的目的是什么?请注意,您可以使用list(itertools.chain(*exc.map(read_sample, files)))
来获取结果,但它既不受线程也不受生成器的好处。 - MisterMiyagilen()
,这意味着列表中元素的数量,而不是所有元素的总大小(这可能是1000 - 就像sum(len(x) for x in files)
)。 - furasmap
查看生成器内部,类似于不存在的map_from
或其他什么东西? - norok2A
对象的列表,每个对象都有一个正则表达式。每个A
对象都需要生成10个B
对象。因此,我正在产生10个B
对象。由于它们都是文件操作并且使用map
函数,我正在尝试将其变成多线程。如果这个POC成功了,我将在我的产品中应用相同的概念。然而,我相信在Python中无论业务逻辑如何,都应该有一种方法来实现这一点。 - Jay Joshi