关于竞争性的白痴症(以反应性编程为例)

1.简介


在我看来,针对程序员的思想,情绪和愿望的竞争是编程开发的一种现代趋势。当几乎没有提出任何建议时,尽管是为此奋斗的口号。在软件范式的迷恋中很难识别出一些新事物,而事实上,新事物通常是众所周知的,有时甚至已经过时了。许多编程语言中的术语愉悦,冗长的分析和多行示例将一切“洗劫了”。同时,要求开放和/或考虑解决方案的背景,顽固地避免了创新的本质,试图找出需要多少以及最终将带来什么结果的尝试,这些创新定性地将创新与已知的方法和编程工具区分开来。

经过一番讨论后,我在哈布雷(Habré)出现,正如其中一次讨论所恰当指出的那样。我什至不介意。至少,显然,印象就是这样。因此,我承认,虽然是我的错,但这只是部分原因。我承认,我依靠上世纪80年代形成的关于并行编程的思想。古代?也许。但是,请告诉我有什么新消息,关于那方面的并行编程科学尚不为人所知(请参阅详细信息[1])。当时,并行程序分为两类-并行串行和异步。如果前者已经被认为是过时的,那么后者-将会是真正的平行。在后者中,带有事件控制的编程(或仅是事件编程),流控制和动态编程被挑出来。一般而言。已经有更多细节。

除了至少40年前已经知道的内容之外,当前的编程还提供什么?在我的“冻僵的表情”中-什么都没有。事实证明,协程现在被称为协程,甚至称为goroutine;并发和竞争这两个术语都变成了昏昏欲睡的人,似乎不仅仅是翻译。而且没有这样的例子。例如,反应式编程(RP)与事件编程或流传输之间有什么区别?它属于哪个已知类别和/或分类?似乎没有人对此感兴趣,也没有人可以澄清这一点。或者您现在可以按名称分类?然后,确实,协程和协程是不同的东西,并且并行编程只是必须不同于竞争程序。那状态机呢?这是什么样的奇迹技术?

头部中的“意大利面条”源自该理论的遗忘,在该理论中,当引入新模型时,会将其与已知的和经过研究的模型进行比较。这样做是否会做得好,但至少您可以弄清楚,因为该过程已正式化。但是,如果给协程命名一个新的昵称,然后同时用五种语言选择“引擎罩代码”,那么如何深入了解它,还评估了向流迁移的前景。而且,这些只是协程,坦率地说,由于它们的基本性质和较小的用途(当然,这与我的经验有关),应该已经将它们遗忘了。

2.反应式编程以及所有,所有,一切


尽管我们将以“反应性示例”作为进一步讨论的基础,但我们不会为自己设定透彻理解“反应性编程”概念的目标。他的正式模型将在众所周知的正式模型的基础上创建。我希望,这将使我们能够清楚,准确,详细地了解原始程序的解释和操作。但是,所创建的模型及其实现将是“反应性的”多少取决于这种类型的编程的辩护者来决定。目前,新模型将必须实现/建模原始示例的所有细微差别。如果没有考虑到某些因素,那么我希望有人能纠正我。

因此,在[2]中,考虑了一个反应式程序的示例,其代码如清单1所示。

清单1.反应性程序代码
1. 1 = 2 
2. 2 = 3 
3. 3 = 1 + 2 
4.  1, 2, 3 
5. 1 = 4 
6.  1, 2, 3


在反应式编程领域,其工作结果将与同类常规程序的结果不同。如果不说丑陋,仅此而已是不好的,因为计划的结果应该是明确的,而不取决于执行情况。但是更多的混淆了对方。首先,在外观上几乎不可能将常规相似代码与反应性代码区分开。其次,显然,作者本人并不完全确定反应式程序的工作,而是说结果“最可能”。第三,哪个结果被认为是正确的?

代码解释中的这种歧义导致了这样一个事实,即不可能立即“切入”该代码。但是,然后,正如通常发生的那样,一切都变得比预期的要简单得多。图1显示了两个结构图,它们希望与该结构相对应并说明示例的操作。在上图中,块X1和X2组织数据输入,向块X3发送有关其更改的信号。后者执行求和并允许Pr块打印变量的当前值。打印后,Pr块将向X3块发出信号,并不仅向他发出信号,而且还向他发出信号,表示他准备打印新值。

图。1.示例的两个结构模型
image

与第一种方案相比,第二种方案非常基础。作为单个块的一部分,它输入数据并按顺序实现:1)计算输入数据的总和,以及2)打印它们。没有公开在此呈现级别的块的内部填充。尽管可以说在结构层面上它可以是一个“黑匣子,包括四个区块的方案。但是,他的[算法]装置应该有所不同。

评论。该程序作为黑匣子的方法实质上反映了用户对其的态度。后者对它的实施不感兴趣,但是对工作的结果感兴趣。无论是响应式程序,事件程序还是其他程序,但是根据算法理论得出的结果都应该是明确且可预测的。

在图。图2给出了详细阐明电路模块内部[算法]结构的算法模型。上层模型由自动机网络表示,其中每个自动机是单独块的算法模型。虚线圆弧所示的自动机之间的连接对应于电路的连接。单自动机模型描述了由一个块组成的框图的操作算法(请参见图1中的另一个Pr块)。

图。2.结构方案的算法模型
image

自动机X1和X2(自动机和块的名称与它们的变量的名称一致),检测更改,如果自动机X3准备执行加法操作(在状态``s0''),则进入状态``s1'',记住变量的当前值。已获得进入状态“ s1”的许可的X3机器执行加法操作,并在必要时等待变量的打印完成。完成打印的“打印机” Pr返回初始状态“ p0”,在此等待下一个命令。请注意,其状态“ p1”开始反向转换链-自动机X3进入状态“ s0”,X1和X2进入状态“ s0”。之后,将对输入数据进行分析,然后对其求和并随后进行打印。

与自动机网络相比,单独的Pr自动机的算法非常简单,但是,我们注意到,它可以完成相同的工作,甚至更快。它的谓词揭示了变量的变化。如果发生这种情况,则从动作y1的开始执行到状态``p1''的转换(见图2),该动作在记住变量的同时总结变量的当前值。然后,在从状态“ p1”到状态“ p0”的无条件转换时,动作y2打印变量。之后,处理返回到输入数据的分析。清单2显示了最新模型的实现代码。

清单2. Pr自动机的实现
#include "lfsaappl.h"
#include "fsynch.h"
extern LArc TBL_PlusX3[];
class FPlusX3 : public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FPlusX3(nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();

    FPlusX3(string strNam, CVarFsaLibrary *pCVFL): LFsaAppl(TBL_PlusX3, strNam, nullptr, pCVFL) { }

    CVar *pVarY;        		// 
    CVar *pVarX1;        		// 
    CVar *pVarX2;        		// 
    CVar *pVarX3;        		// 
    CVar *pVarStrNameX1;		//   X1
    CVar *pVarStrNameX2;		//   X2
    CVar *pVarStrNameX3;		//   X3
protected:
    int x1(); int x2();
    int x12() { return pVarX1 != nullptr && pVarX2 && pVarX3; };
    void y1();
    void y12() { FInit(); };
    double dSaveX1{0};
    double dSaveX2{0};
};

#include "stdafx.h"
#include "fplusx3.h"

LArc TBL_PlusX3[] = {
    LArc("st",		"st","^x12","y12"), 		//
    LArc("st",		"p0","x12",	"--"),			//
    LArc("p0",		"p1","x1",  "y1"),			//
    LArc("p0",		"p1","x2",  "y1"),			//
    LArc("p1",		"p0","--",  "--"),			//
    LArc()
};

// creating local variables and initialization of pointers
bool FPlusX3::FCreationOfLinksForVariables() {
// creating local variables
    pVarY = CreateLocVar("strY", CLocVar::vtString, "print of output string");			//  
    pVarX1 = CreateLocVar("dX1", CLocVar::vtDouble, "");			//  
    pVarX2 = CreateLocVar("dX2", CLocVar::vtDouble, "");			//  
    pVarX3 = CreateLocVar("dX3", CLocVar::vtDouble, "");			//  
    pVarStrNameX1 = CreateLocVar("strNameX1", CLocVar::vtString, "");			//   
    pVarStrNameX2 = CreateLocVar("strNameX2", CLocVar::vtString, "");			//   
    pVarStrNameX3 = CreateLocVar("strNameX3", CLocVar::vtString, "");			//   
// initialization of pointers
    string str;
    str = pVarStrNameX1->strGetDataSrc();
    if (str != "") { pVarX1 = pTAppCore->GetAddressVar(str.c_str(), this);	}
    str = pVarStrNameX2->strGetDataSrc();
    if (str != "") { pVarX2 = pTAppCore->GetAddressVar(str.c_str(), this);	}
    str = pVarStrNameX3->strGetDataSrc();
    if (str != "") { pVarX3 = pTAppCore->GetAddressVar(str.c_str(), this);	}
    return true;
}

int FPlusX3::x1() { return pVarX1->GetDataSrc() != dSaveX1; }
int FPlusX3::x2() { return pVarX2->GetDataSrc() != dSaveX2; }

void FPlusX3::y1() {
// X3 = X1 + X2
    double dX1 = pVarX1->GetDataSrc(); double dX2 = pVarX2->GetDataSrc();
    double dX3 = dX1 + dX2;
    pVarX3->SetDataSrc(this, dX3);
    dSaveX1 = dX1; dSaveX2 = dX2;
//  1, 2, 3
    QString strX1; strX1.setNum(dX1); QString strX2; strX2.setNum(dX2);
    QString strX3; strX3.setNum(dX3);
    QString qstr = "X1=" + strX1 + ", X2=" + strX2 + ", X3=" + strX3;
    pVarY->SetDataSrc(nullptr, qstr.toStdString(), nullptr);
}


代码量显然比原始示例大得多。但是,请注意,不是一个单一的代码。新的解决方案消除了所有功能上的问题,不允许在解释程序时遇到幻想。看起来紧凑而优雅,但是您可以说“最有可能”的示例并不会引起积极的情绪和与之合作的渴望。还应注意,有必要将实际值与自动机y1的作用进行比较。

其余代码与“自动环境”的要求有关,我注意到,在源代码中并未提及。因此,基本自动机类LFsaApplFCreationOfLinksForVariables方法当在VKPA环境级别指示与它们关联的其他环境变量的符号名称时,为机器创建本地变量并链接到它们。它是在创建自动机时首次启动,然后在FInit方法的框架内启动(请参见步骤y12),因为创建对象时并非所有链接都是已知的。机器将处于“ st”状态,直到初始化x12谓词检查的所有必要链接。如果给定变量名,则返回该变量的GetAddressVar方法。

为了消除可能的问题,我们介绍了自动机网络的代码。清单3中显示了它,其中包括三个自动机类的代码。以此为基础,创建了许多对象,它们对应于图1中所示的网络结构图。1.请注意,对象X1和X2派生自通用类FSynch。

清单3.自动化网络类
#include "lfsaappl.h"

extern LArc TBL_Synch[];
class FSynch : public LFsaAppl
{
public:
    double dGetData() { return pVarX->GetDataSrc(); };
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FSynch(nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();

    FSynch(string strNam, CVarFsaLibrary *pCVFL): LFsaAppl(TBL_Synch, strNam, nullptr, pCVFL) { }

    CVar *pVarX;			// 
    CVar *pVarStrNameX;		//   
    CVar *pVarStrNameObject;//  -
    LFsaAppl *pL {nullptr};
protected:
    int x1() { return pVarX->GetDataSrc() != dSaveX; }
    int x2() { return pL->FGetState() == "s1"; }
    int x12() { return pL != nullptr; };
    void y1() { dSaveX = pVarX->GetDataSrc(); }
    void y12() { FInit(); };
    double dSaveX{0};
};

#include "stdafx.h"
#include "fsynch.h"

LArc TBL_Synch[] = {
    LArc("st",		"st","^x12","y12"), 		//
    LArc("st",		"s0","x12",	"y1"),			//
    LArc("s0",		"s1","x1",  "y1"),			//
    LArc("s1",		"s0","x2",	"--"),			//
    LArc()
};

// creating local variables and initialization of pointers
bool FSynch::FCreationOfLinksForVariables() {
// creating local variables
    pVarX = CreateLocVar("x", CLocVar::vtDouble, " ");
    pVarStrNameX = CreateLocVar("strNameX1", CLocVar::vtString, "name of external input variable(x1)");			//   
    pVarStrNameObject = CreateLocVar("strNameObject", CLocVar::vtString, "name of function");                   //  
// initialization of pointers
    string str;
    if (pVarStrNameX) {
        str = pVarStrNameX->strGetDataSrc();
        if (str != "") { pVarX = pTAppCore->GetAddressVar(str.c_str(), this);	}
    }
    str = pVarStrNameObject->strGetDataSrc();
    if (str != "") { pL = FGetPtrFsaAppl(str);	}
    return true;
}

#include "lfsaappl.h"
#include "fsynch.h"

extern LArc TBL_X1X2X3[];
class FX1X2X3 : public LFsaAppl
{
public:
    double dGetData() { return pVarX3->GetDataSrc(); };
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FX1X2X3(nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();

    FX1X2X3(string strNam, CVarFsaLibrary *pCVFL): LFsaAppl(TBL_X1X2X3, strNam, nullptr, pCVFL) { }

    CVar *pVarX1{nullptr};			//
    CVar *pVarX2{nullptr};			//
    CVar *pVarX3{nullptr};			//
    CVar *pVarStrNameFX1;		//  X1
    CVar *pVarStrNameFX2;		//  X2
    CVar *pVarStrNameFPr;		//  Pr
    CVar *pVarStrNameX3;		//   
    FSynch *pLX1 {nullptr};
    FSynch *pLX2 {nullptr};
    LFsaAppl *pLPr {nullptr};
protected:
    int x1() { return pLX1->FGetState() == "s1"; }
    int x2() { return pLX2->FGetState() == "s1"; }
    int x3() { return pLPr->FGetState() == "p1"; }
    int x12() { return pLPr != nullptr && pLX1 && pLX2 && pVarX3; };
    void y1() { pVarX3->SetDataSrc(this, pLX1->dGetData() + pLX2->dGetData()); }
    void y12() { FInit(); };
};
#include "stdafx.h"
#include "fx1x2x3.h"

LArc TBL_X1X2X3[] = {
    LArc("st",		"st","^x12","y12"), 		//
    LArc("st",		"s0","x12",	"--"),			//
    LArc("s0",		"s1","x1",  "y1"),			//
    LArc("s0",		"s1","x2",  "y1"),			//
    LArc("s1",		"s0","x3",	"--"),			//
    LArc()
};
// creating local variables and initialization of pointers
bool FX1X2X3::FCreationOfLinksForVariables() {
// creating local variables
    pVarX3 = CreateLocVar("x", CLocVar::vtDouble, " ");
    pVarStrNameFX1 = CreateLocVar("strNameFX1", CLocVar::vtString, "");
    pVarStrNameFX2 = CreateLocVar("strNameFX2", CLocVar::vtString, "");
    pVarStrNameFPr = CreateLocVar("strNameFPr", CLocVar::vtString, "");
    pVarStrNameX3 = CreateLocVar("strNameX3", CLocVar::vtString, "");
// initialization of pointers
    string str; str = pVarStrNameFX1->strGetDataSrc();
    if (str != "") { pLX1 = (FSynch*)FGetPtrFsaAppl(str);	}
    str = pVarStrNameFX2->strGetDataSrc();
    if (str != "") { pLX2 = (FSynch*)FGetPtrFsaAppl(str);	}
    str = pVarStrNameFPr->strGetDataSrc();
    if (str != "") { pLPr = FGetPtrFsaAppl(str);	}
    return true;
}
#include "lfsaappl.h"
#include "fsynch.h"

extern LArc TBL_Print[];
class FX1X2X3;
class FPrint : public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FPrint(nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();

    FPrint(string strNam, CVarFsaLibrary *pCVFL): LFsaAppl(TBL_Print, strNam, nullptr, pCVFL) { }

    CVar *pVarY;        		// 
    CVar *pVarStrNameFX1;		//    X1
    CVar *pVarStrNameFX2;		//    X2
    CVar *pVarStrNameFX3;		//    X3
    FSynch *pLX1 {nullptr};     //    X1
    FSynch *pLX2 {nullptr};     //    X2
    FX1X2X3 *pLX3 {nullptr};    //    X3
protected:
    int x1();
    int x12() { return pLX3 != nullptr && pLX1 && pLX2 && pLX3; };
    void y1();
    void y12() { FInit(); };
};
#include "stdafx.h"
#include "fprint.h"
#include "fx1x2x3.h"

LArc TBL_Print[] = {
    LArc("st",		"st","^x12","y12"), 		//
    LArc("st",		"p0","x12",	"--"),			//
    LArc("p0",		"p1","x1",  "y1"),			//
    LArc("p1",		"p0","--",	"--"),			//
    LArc()
};
// creating local variables and initialization of pointers
bool FPrint::FCreationOfLinksForVariables() {
// creating local variables
    pVarY = CreateLocVar("strY", CLocVar::vtString, "print of output string");			//  
    pVarStrNameFX1 = CreateLocVar("strNameFX1", CLocVar::vtString, "name of external input object(x1)");			//   
    pVarStrNameFX2 = CreateLocVar("strNameFX2", CLocVar::vtString, "name of external input object(x2)");			//   
    pVarStrNameFX3 = CreateLocVar("strNameFX3", CLocVar::vtString, "name of external input object(pr)");			//   
// initialization of pointers
    string str;
    str = pVarStrNameFX1->strGetDataSrc();
    if (str != "") { pLX1 = (FSynch*)FGetPtrFsaAppl(str);	}
    str = pVarStrNameFX2->strGetDataSrc();
    if (str != "") { pLX2 = (FSynch*)FGetPtrFsaAppl(str);	}
    str = pVarStrNameFX3->strGetDataSrc();
    if (str != "") { pLX3 = (FX1X2X3*)FGetPtrFsaAppl(str);	}
    return true;
}

int FPrint::x1() { return pLX3->FGetState() == "s1"; }

void FPrint::y1() {
    QString strX1; strX1.setNum(pLX1->dGetData());
    QString strX2; strX2.setNum(pLX2->dGetData());
    QString strX3; strX3.setNum(pLX3->dGetData());
    QString qstr = "X1=" + strX1 + ", X2=" + strX2 + ", X3=" + strX3;
    pVarY->SetDataSrc(nullptr, qstr.toStdString(), nullptr);
}


该代码与清单1不同,例如其设计文档中的飞机图片。但是,我认为我们主要是程序员,有些设计师不会告诉他们。我们的“设计代码”应易于理解且明确解释,以使我们的“飞机”不会在首次飞行时坠毁。而且,如果发生了这样的不幸,并且与程序相比,发生这种情况的机会比飞机多得多,那么可以轻松迅速地找到原因。

因此,考虑清单3,您需要假设类的数量与并行程序中相应对象的数量没有直接关系。该代码不反映对象之间的关系,但是包含创建对象的机制。因此,FSynch包含指向类型为对象的pL指针LFsaAppl。该对象的名称由局部变量确定,该局部变量在VKPa环境中将与名称为strNameObject的自动机变量相对应。必须有一个指针才能使用FGetState方法监视FSynch类型的自动机对象的当前状态(请参阅谓词代码x2)。指向对象的类似指针,用于指定对象名称的变量以及组织关系所必需的谓词包含其他类。

现在,简单介绍一下VKPA环境中并行程序的“构造”。它是在加载程序配置期间创建的。在这种情况下,第一个对象是根据自动机类型的主题动态库中的类创建的(它们的集合由应用程序/程序的配置确定)。创建的对象由它们的名称标识(我们称它们为自动变量然后,将必要的值写入自动机的局部变量。在我们的例子中,将字符串类型的变量设置为其他对象的变量名称和/或对象的名称。这样,在并行自动机程序的对象之间建立了连接(参见图1)。此外,更改输入变量的值(使用单个对象控制对话框或标准对话框/环境对话框来设置环境变量的值),我们可以固定结果。可以使用标准的环境对话框来显示变量的值。

3.对并行程序的分析


关于并行程序的功能,除非非常简单的顺序并行,否则很难说出具体的东西。所考虑的自动机网络也不例外。接下来,我们将看到这一点,了解可以从中得到什么。

生成的自动机和为其构建的网络如图2所示。3.从图中的网络。如图2所示,除了重命名其元素-自动机,输入和输出信号外,它还以没有变量的“印刷机”为特色。后者对于网络的运行不是必需的,重命名使您可以使用合成操作来构建生成的自动机。另外,为了创建较短的名称,例如当自动机A的状态“ a0”由符号“ 0”表示,而“ a1”由符号“ 1”表示时,引入了编码。其他机器也一样。在这种情况下,网络的组件状态(例如“ a1b0c1”)被分配为名称“ 101”。类似地,为网络的所有组件状态形成名称,其数量由组件自动机状态的乘积确定。

图。3.产生的网络自动机
image

生成的自动机当然可以以纯粹形式的方式来计算,但是为此,我们需要一个适当的“计算器”。但是,如果不是这样,则可以使用相当简单的直观算法。在其框架内,记录网络的一个或另一种组件状态,然后对所有可能的输入情况进行分类,由“句柄”确定目标组件状态。因此,在固定了与组件自动机的当前状态相对应的状态“ 000”-“ a0”,“ b0”,“ c0”之后,确定了输入变量^ x1 ^ x2,^ x1x2,x1 ^ x2,x1x2的合取的过渡。状态“ a0b0c0”,“ a0b1c0”,“ a1b0c0”,“ a1b1c0”,在生成的机器上分别标记为“ 000”,“ 010”,“ 100”和“ 110”,对于所有可达到的状态,必须依次重复此操作。循环可以从图中排除未加载操作的操作。

我们所拥有的“干残渣中”。我们达到了主要目的-我们收到了自动机,它可以准确地描述网络的运行。我们发现,在八个可能的网络状态中,一个是不可访问的(隔离的)状态-“ 001”。这意味着在任何情况下都不会为未更改当前值的输入变量触发求和操作。

尽管测试没有发现错误,但是这令人不安。在生成的自动机图上,发现输出动作中发生冲突的过渡。它们用动作y1y3和y2y3的组合标记。输入数据更改时,将触发动作y1和y2,然后另一个动作y3并行计算变量的总和。它会以什么价值运作-旧的或刚刚被新的改变?为了消除歧义,您可以简单地更改y3和y4的动作。在这种情况下,它们的代码如下:X3 = X1Sav + X2Sav并打印(X1Sav,X2Sav,X3)。

所以。生成的自动机的构造在创建的并行模型中显示出明显的问题。它们是否出现在反应式程序中是一个问题。显然,一切都将取决于在反应性范例中实现并行性的方法。在任何情况下,都必须考虑并以某种方式消除这种依赖性。对于自动网络,保留更改的版本比尝试更改网络更容易。可以先打印启动网络操作的“旧”数据,然后再打印当前数据。

4。结论


所考虑的每个解决方案都有其优点和缺点。最初的非常简单,网络更复杂,并且是在单台机器的基础上创建的,只有在可视化之后,它才会开始分析输入数据。由于其并行性,同一自动网络将在打印过程结束之前开始分析输入数据。而且如果可视化时间很长,但是对于求和运算将是这种情况,那么从输入控制的角度来看,网络将更快。那些。在并行程序的情况下,基于对代码量的估计的评估并不总是客观的。简单来说,网络是并行的,单组件解决方案在很大程度上是顺序的(其谓词和操作是并行的)。首先,我们正在谈论并行程序。

网络模型也是灵活解决方案的一个示例。首先,组件可以彼此独立设计。其次,任何组件都可以替换为另一个组件。第三,任何网络组件都可以是自动过程库的元素,并可以在另一个网络解决方案中使用。而这些仅仅是并行解决方案最明显的好处。

但是回到反应式编程。 RP是否认为所有程序语句最初都是并行的?我们只能假设没有这个,就很难谈论“面向数据流和变化传播”的编程范式(参见[3]中的反应式编程的定义)。但是,它与使用流控制进行编程有什么区别(有关更多详细信息,请参见[1])?因此,我们回到开始的地方:如何在知名分类框架内对反应式编程进行分类?而且,如果RP是某种特殊的编程,那么它与已知的编程范例有什么不同?

好吧,关于理论。没有它,并行算法的分析将不仅困难,而且不可能。分析过程有时会发现一些问题,即使对程序进行了仔细和周到的考虑(顺便说一下,在“设计文档”中),也无法猜测。无论如何,我认为飞机无论是具有象征意义还是从其他意义上来说都不会坠毁。这是我的事实,当然,您需要努力争取形式的简洁和优雅,但又不失质量。我们,程序员,不仅是“绘制”程序,而且还经常控制飞机上隐藏的内容!

是的,我差点忘了。我将自动编程(AP)归类为具有动态控制的编程。至于异步-我敢打赌。假设AP控制模型的基础是单一时间的网络,即同步网络的自动机,那么它就是同步的。但是由于VKPa环境还通过“自动机世界”的概念实现了许多网络,因此它是完全异步的。总的来说,我反对任何非常严格的分类框架,但不反对无政府状态。从这个意义上讲,我希望在VKPa中,可以在串行并行编程的刚性和某种异步无政府状态之间达成某种折衷。鉴于自动编程还涵盖事件程序的类(请参见[4]),并且流程序很容易在其中建模,您仍然梦想着什么编程?当然-对我来说。

文献
1. /.. , .. , .. , .. ; . .. . – .: , 1983. – 240.
2. . [ ], : habr.com/ru/post/486632 . . . ( 07.02.2020).
3. . . [ ], : ru.wikipedia.org/wiki/_ . . . ( 07.02.2020).
4. — ? [ ], : habr.com/ru/post/483610 . . . ( 07.02.2020).

Source: https://habr.com/ru/post/undefined/


All Articles