Python工作流设计模式

Eel*_*orn 19 python workflow

我正在研究一个软件设计,我不知道自己在做什么,感觉我正在重新发明轮子.

我的情况如下:我正在设计一个具有交互式UI的科学实用程序.用户输入应该触发视觉反馈(duh),其中一些是直接的,即编辑域几何,以及其中的一些尽快,而不会阻止用户交互,比如在所述域上解决一些PDE.

如果我绘制出我需要执行的所有操作的图表,我会得到这个相当令人敬畏的密集图形,暴露各种并行机会和缓存/重用部分结果.所以我想要的主要是以透明的方式利用这种并行性(选择的子任务在单独的进程中执行,结果由下游任务"加入"等待所有输入准备就绪),加上只需要重新计算那些输入分支实际上他们的输入改变了

pyutilib.workflow似乎最接近我正在寻找的东西,当然它不是(似乎没有做任何子处理开始).这似乎相当令人失望; 虽然我不是软件工程师,但我会说这里不要求任何疯狂的东西.

另一个复杂因素是我想要的紧密的用户界面集成,其他科学工作流程解决方案似乎无法处理.例如,我想通过转换节点传递拖放事件以进行进一步处理.转换节点有两个输入; 仿射变换状态输入端口,以及知道如何处理它的pointset类.如果仿射变换输入端口为"脏"(等待其依赖项更新),则应该保持该事件直到它变为可用.但是当事件通过节点时,eventinput端口应该被标记为已处理,因此当仿射变换由于进一步的用户输入而改变时它不会重新发送.这只是我出现的许多问题中的一个例子,我看不到任何问题.或者当长时间运行的分叉连接分支在处理前一个输入的过程中接收到新输入时该怎么办.

所以我的问题:您是否碰巧知道我应该阅读的有关工作流设计模式的一些好书/文章?或者我是否想要将方形钉子装入圆孔中,你知道我应该知道的完全不同的设计模式吗?或者是一个python包,可以实现我想要的功能,无论它装扮成什么流行语?

我已经在enthought.traits之上推出了自己的解决方案,但我对此并不十分满意,因为它感觉就像轮子的粗糙和粗制滥造一样.除了我似乎无法在互联网上的任何地方找到任何轮子.

注意:我不是在寻找webframeworks,图形工作流设计器或任何专用工具.只是概念上像pyutilib.workflow的东西,但包括文档和我可以使用的功能集.

###编辑:这是我在阅读和思考问题之后的所在:###

一个人可以应对"工作流程架构"的要求太多样化,因此没有适合所有人的单一鞋子.您是否希望与磁盘存储紧密集成,与Web框架紧密集成,异步性,混合使用自定义有限状态机逻辑进行任务调度?它们都是有效的要求,它们在很大程度上是不兼容的,或者是无意义的混音.

然而,并非所有人都失去了.寻找一个通用的工作流系统来解决任意问题就像寻找一个通用的迭代器来解决你的自定义迭代问题.迭代器主要不是关于可重用性; 你不能重用你的红黑树迭代器迭代你的张量.它们的优势在于关注点的清晰分离以及统一界面的定义.

我正在寻找的(并且已经开始自己编写;它会非常酷)看起来像这样:它的基础是一个通用的实现无关的工作流声明迷你语言,基于装饰器和一些元魔法,将以下语句转换为包含所有必需信息的工作流声明:

@composite_task(inputs(x=Int), outputs(z=Float))
class mycompositetask:
    @task(inputs(x=Int), outputs(y=Float))
    def mytask1(x):
        return outputs( y = x*2 )
    @task(inputs(x=Int, y=Float), outputs(z=Float))
    def mytask2(x, y):
        return outputs( z = x+y )
    mytask1.y = mytask2.y   #redundant, but for illustration; inputs/outputs matching in name and metadata autoconnect
Run Code Online (Sandbox Code Playgroud)

装饰器返回的是task/compositetask/workflow 声明类.而不仅仅是键入约束,手头工作流类型所需的其他元数据很容易添加到语法中.

现在,这个简洁和pythonic声明可以输入到返回实际工作流实例的工作流实例工厂中.这种声明语言非常通用,并且可能不需要在不同的设计要求之间进行很大的改变,但是这样的工作流实例化工厂完全取决于您的设计要求/想象,除了用于传递/检索输入/输出的通用接口.

在其最简单的化身中,结婚有类似于:

wf   = workflow_factory(mycompositetask)
wf.z = lambda result: print result   #register callback on z-output socket
wf.x = 1    #feed data into x input-socket
Run Code Online (Sandbox Code Playgroud)

其中wf是一个简单的工作流实例,一旦所有输入都被绑定,它只会在同一个线程上链接所有包含的函数体.链接两个函数的一种非常冗长的方式,但它说明了这个想法,并且它已经实现了将信息流的定义保持在一个中心位置而不是在整个类中分散的关注的目标.做它.

这或多或少是我迄今为止实现的功能,但这意味着我可以继续处理我的项目,并在适当的时候添加对更高级的工作流实例工厂的支持.例如,我正在考虑分析依赖关系图以识别分支和连接,并跟踪工作流实例级别上提供的每个输入所生成的活动,以实现优雅的负载平衡和取消丢失的特定输入的影响它们的相关性,但仍在占用资源.

无论哪种方式,我认为分离工作流声明,接口定义和实例化实现的项目是值得的.一旦我有一些非常重要类型的工作流实例运行良好(我需要至少两个用于我正在进行的项目,我已经意识到*),我希望找到时间将其作为一个公共项目发布,因为尽管工作流系统中设计要求的多样性,涵盖了这一基础,使得实现您自己的特定要求变得更加简单.而不是一个臃肿的工作流程框架,一个易于切换的定制解决方案的瑞士军刀可以围绕这样的核心成长.

*意识到我需要将我的代码分成两个不同的工作流实例类型,而不是试图将我的所有设计要求都压缩成一个解决方案,将我心中的方形钉和圆孔转换成两个完美互补的孔和钉.

and*_*uso 18

我相信你是对,错,对于重新发明轮子有疑问.也许不同的思维水平给你一个暗示.

怎么吃大象?

A级:软件设计

在这个级别,您可能希望坚持在UI(和UI线程)中不进行长时间操作的最佳实践.您需要一个仅关注于收集输入(包括取消)和绘图(包括进度条形图或小时玻璃等进行中可视化)的UI图层.这层应该与黄昏和黎明之间的任何其他东西分开.如果您需要直观性和响应性,那么此层之外的任何调用都必须快速.

在与您一样复杂的任务中,UI层外部的调用通常是:

  1. Schecule一些工作 - 命令应该排队到智能层,以便它可以在它到达时获取.
  2. 读取结果 - 结果应该在智能层中排队,这样它们就可以"弹出"并呈现.
  3. 取消/停止/退出 - 只需举起一面旗帜.智能层应该立即检查此标志.

不要太担心一些用户操作反应太慢 - 如果你有一个坚实的设计核心,那么你可以稍后调整用户输入的优先级.或者添加短期沙漏或类似物.或者甚至取消在特定用户输入后过时的所有长时间操作.

B级:重型智能

对于"任何"的艰苦工作,没有"最佳"框架.

因此,我建议您尽可能简单地设计此层的馈送(通过UI),不涉及任何框架.

在内部,您可以使用某些框架实现它,但您将来有能力根据需要重新设计硬工作元素.例如,将来您可以:

  • 给GPU一些数学
  • 将任务共享到服务器场
  • 涉及云计算

对于复杂的任务,在顶层设计中选择框架可能会成为未来的障碍.具体而言,它可能会限制您应用其他技术的自由.

这很难说清楚,但在我看来,你没有为你的任务设置一个银弹框架.因此,您应该找到强大的工具(例如线程和队列)来实现良好的设计实践(例如,解耦).

编辑作为对您的编辑的回复

您的最新编辑完美地强调了软件设计人员遇到的难题.对于你的情况,接受没有银弹.我建议你尽早接受 - 比以后更好......

提示的原因在于您提供了由Int和Float定义的最通用的任务.这可能会让你为今天感到高兴,但明天会失败.正如锁定到超抽象框架一样.

路径是正确的 - 在您的设计中拥有一个繁重的"任务"基础.但它不应该定义Int或Float.重点关注上面提到的"开始","阅读"和"停止".如果你没有看到你正在吃的大象的大小那么你可能会失败吃它并最终饿死:)

从A级 - 设计角度来看 - 您可以定义任务以包含以下内容:

class AnySuperPowerfulTask:
    def run():
        scheduleForAThreadToRunMe()
    def cancel():
        doTheSmartCancellationSoNobodyWouldCrash()
Run Code Online (Sandbox Code Playgroud)

这为您提供了基础 - 中性,但清洁,并通过A级(设计)视角解耦.

但是,您需要某种设置任务并获得真实结果,对吧?当然,那将属于思维B级.它将特定于任务(或作为中间基础实现的一组任务).最后的任务可能是这样的:

class CalculatePossibilitiesToSaveAllThePandas(SuperPowerfulTask):
    def __init__(someInt, someFloat, anotherURL, configPath):
        anythingSpecificToThisKindOfTasks()
    def getResults():
        return partiallyCalculated4DimensionalEvolutionGraphOfPandasInOptimisticEnvoronment()
Run Code Online (Sandbox Code Playgroud)

(python故意不正确的样本,以便专注于设计,而不是语法).

C级 - 抽象 - 必杀技

看起来这个级别应该在这篇文章中提到.

是的,许多优秀的设计师都可以确认存在这样的陷阱.你可以无休止地(并且没有任何结果)搜索"通用解决方案"的状态,即银弹.我建议你先看看这个,然后在太晚之前快速离开;)陷入这个陷阱并不是耻辱 - 这是最伟大设计师的正常发展阶段.至少我想这么相信:)

编辑2

你说:"我正在研究一个软件设计,不知道我在做什么,感觉就像我重新发明轮子一样."

任何软件设计师都会陷入困境.也许下一层次的思考可能会帮助你.它来了:

D级 - 我被卡住了

建议.离开大楼.走进咖啡馆的下一个角落,点上最好的咖啡,坐下来.问自己一个问题"我需要什么?".请注意,它与"我想要什么?"的问题不同.Ping它直到你消除了错误的答案并开始观察正确的答案:

错误的答案:

  1. 我需要一个可以做X,Y和Z的框架.
  2. 我需要一把可以跑200英里的螺丝刀在附近的农场收割森林.
  3. 我需要一个令人惊讶的内部结构,我的用户实际上永远看不到.

正确的答案(如果我理解你的问题错了,请原谅我):

  1. 我需要用户能够为软件提供输入.
  2. 我需要用户看到计算正在进行中.
  3. 我需要用户直观地看到计算结果.