funworker
轻量级线程流水线框架:生产者 -> 队列 -> 处理单元线程池 -> 队列 -> 消费者,各阶段通过队列解耦。
下游只需要继承三个基类、实现一个方法,就能获得一条可优雅启停的多线程流水线:
| 角色 | 基类 | 需要实现 |
|---|---|---|
| 生产者 | BaseProducer |
produce(self) -> Any |
| 处理单元 | BaseProcessor |
process(self, item) -> Any |
| 消费者 | BaseConsumer |
consume(self, item) -> None |
WorkerPool 负责把 BaseProcessor 包装成多线程执行;Pipeline 负责把它们串起来,提供一个 run()
方法统一管理启动/停止——下游不需要接触 producer/consumer 内部的线程细节。
安装
pip install -e .
快速上手
from funworker import BaseConsumer, BaseProcessor, BaseProducer, Pipeline, SKIP
class NumberProducer(BaseProducer):
def __init__(self, *args, total=10, **kwargs):
super().__init__(*args, **kwargs)
self._total = total
self._current = 0
def produce(self):
if self._current >= self._total:
raise StopIteration # 数据生产完毕(有限任务场景)
value = self._current
self._current += 1
return value
class SquareProcessor(BaseProcessor):
def process(self, item):
result = item * item
return (
result if result % 2 == 0 else SKIP
) # SKIP 表示丢弃这条数据;None 是合法业务值
class PrintConsumer(BaseConsumer):
def consume(self, item):
print(f"result = {item}")
pipeline = Pipeline.build(
producer_cls=NumberProducer,
processor=SquareProcessor, # 也可以传实例,或一个返回实例的工厂函数
consumer_cls=PrintConsumer,
num_workers=4,
)
pipeline.run() # 启动并阻塞:生产者自然结束,或收到 SIGINT/SIGTERM 后,自动优雅停止整条流水线
print(pipeline.stats())
不用 run() 阻塞、而是想在流水线运行期间做别的事情(轮询指标等)时,用 with 语法:进入时自动
启动,退出时自动优雅停止排空,全程不需要访问 producer.join()。BaseProducer/BaseConsumer/
WorkerPool/Pipeline 都支持 with。
示例
example/ 目录下有更多可以直接运行的完整示例,其他仓库可以直接参考/复制:
| 示例 | 说明 |
|---|---|
basic_usage.py |
最小可运行示例:run() 与 with 两种用法 |
multi_stage_pipeline.py |
串联多级处理:add_stage() + set_consumer() |
fan_out_fan_in.py |
一拆多 Many(fan-out)+ 多合一 BaseBatchProcessor(fan-in / 批处理) |
retry_dead_letter_queue.py |
失败重试 + 死信队列 |
progress_logging.py |
运行时进度日志:CountingQueue + format_progress()/log_progress() |
特性
run()一步启停:Pipeline.run()内部处理启动顺序、SIGINT/SIGTERM优雅停止、异常传播, 下游不需要手动调用producer.join()。SKIP/None语义分离:produce()/process()返回None是合法的业务数据;返回funworker.SKIP才表示"丢弃这条,不进入下游队列"。- 异常传播:任一线程内部抛出未捕获异常,会被捕获并在
join()/stop()/run()时重新抛出, 不会静默崩溃。 - 失败重试 + 死信队列:
WorkerPool(..., max_retries=3, dead_letter_queue=dlq),处理失败的数据 会重新排队重试,重试耗尽后写入死信队列(不配置则丢弃并记录日志)。见retry_dead_letter_queue.py。 - 监控指标:
producer.stats()/pool.stats()/consumer.stats()/pipeline.stats()返回 已处理/失败/重试计数、队列长度、线程存活状态,方便接入监控。 - 多级流水线:
pipeline.add_stage(processor2, num_workers=2)可以在第一级处理单元后追加更多级, 上一级的输出队列自动作为下一级的输入队列;最后用pipeline.set_consumer(ConsumerCls)挂消费者。见multi_stage_pipeline.py。 - 幂等停止:
stop()/pool.stop()重复调用是安全的,第二次起直接返回。 - 按 CPU 核数自适应:
num_workers不传时默认取os.cpu_count(),多数场景不需要手动调线程数。 - 一拆多(fan-out)/ 多合一(fan-in):
process()返回funworker.Many([...])把一条拆成多条; 继承BaseBatchProcessor实现process_batch(items)把多条合成一批处理,停止时缓冲区剩余数据 也会强制产出,不丢数据。见fan_out_fan_in.py。 - 批量消费:继承
BaseBatchConsumer实现consume_batch(items),攒够batch_size(默认100) 条或超过batch_timeout(默认10秒)没攒满,就会触发一次批量写入;停止时缓冲区剩余数据也会强制 消费一次,不丢数据,适合批量落库等下游场景。 - 运行时进度日志:
format_progress()/log_progress()(BaseProducer/WorkerPool/BaseConsumer/Pipeline都有),统一"名字(当前/历史)"三段式,每一段的名字都可以单独设置; 配合funworker.CountingQueue还能看到每条队列的历史累计吞吐量。见progress_logging.py。 with语法:BaseWorker(因此BaseProducer/BaseConsumer)、WorkerPool、Pipeline都实现了__enter__/__exit__,避免忘记调用停止方法导致线程泄漏。
设计要点
- 职责分离:
BaseProcessor完全不感知线程/队列,只关心"一条数据怎么处理",方便单测和复用。 - 每线程独立实例:
WorkerPool默认给每个线程创建独立的BaseProcessor实例(传类或工厂函数即可), 处理单元可以放心持有数据库连接、http session 等非线程安全资源。 - 优雅停止:内部使用
STOP哨兵对象 +Queue.join()drain,保证停止前把队列里已有数据处理完, 不丢数据。 - 错误隔离与可见性:单条数据处理异常默认走
on_error钩子记录日志(并按配置重试/进死信队列), 不会打断整条流水线;但线程自身崩溃(如on_start抛异常)会被显式传播给调用方,不会被吞掉。 - 可扩展:
Pipeline是对BaseProducer+ 一至多级WorkerPool+BaseConsumer的编排,add_stage()/set_consumer()让多级处理流水线的写法和单级一样简单。
Metadata
Release files for funworker 0.1.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| funworker-0.1.5-py3-none-any.whl | Python 3 | none | any | Details |
Release files / funworker-0.1.5-py3-none-any.whl
| Download URL | funworker-0.1.5-py3-none-any.whl |
|---|---|
| Size | 24.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ab8e4e1ffefb3275d8d4b7ee712f878eabf7bd49ebb24e7939738feb0237e5f8
|
|
BLAKE2b-256 checksum How to use checksums |
888c29907eb14a85864d4472b3f09e0dfd3126ff39faf2d8a8dbd27dfa8ca5cd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|