1.简介
学会飞行的人将不再爬行。但是原则上也不应傲慢自大。两者都很正常。两者都受到尊重和光荣。对于一个人来说,这就像选择一个职业:按照惯例,您要么是飞行员,要么是驾驶员。对于相同的动物,它是相同的-您是鹰还是狼,即你是飞还是跑(逃跑)但是只有一个人在他的概念,类别,态度和思想上赋予人物以特征,并发展他对它们的态度。确实,有细微差别。因此,没有,它可能比飞行员的职业更光荣和浪漫,但请尝试说服卡车司机或飞机设计师吗?这里很难争辩:即使现在有很多宇航员,仍然没有第二任女王!
我们是程序员。也许在不同程度上,但是有些-可以肯定。我的意思是我们与众不同,我们也可以以不同的方式思考。程序员只认为始终如一的说法就像一个人只奔跑一样,是单方面的,有害的甚至是亵渎的。他有时-会飞。有些人像飞行员一样经常这样做,而有些像宇航员甚至连续数月都这样做。思维一致的想法削弱了人类的能力。在某些时候和一段时间内,您甚至可以相信它,但是“一切都一样,它变成了”-这是关于生命早晚会付出代价的事实。
用图形表示,Asyncio是一个软件拐杖,可以模仿不正确的并行思维。一种用挥动的手弹跳。有时看起来很滑稽又笨拙。尽管在某些情况下这也是一种出路:您可以越过水坑变脏,但是如果力量允许,则最好跳过。但是也许程序员缺乏实力吗?
让我们尝试放弃强加的“软件拐杖”,并超越软件例程。而且不要让它跳得太高,或者不要太远太远,但还是要保持飞行,特别是与拐杖相比。毕竟,一旦Mozhaisky Alexander Fedorovich(不要与莫斯科地区的Mozhaisky市法院混淆;)或同一位莱特兄弟第一次克服了数百米的高空。是的,现代飞机的测试从跑道和与跑道的短期隔离开始。
2. asyncio一个非常简单的示例
我们将从使用Python开始飞行开始。飞行程序很简单。有一些飞机(但是,在蜘蛛图像的原始版本中,请参见[1]),其机身名称分别为“博客”,“新闻”,“论坛”。他们在同一时间起飞。每个人都必须在特定时间内飞过一段路,然后扔一个标有经过路段数量的旗帜。这必须完成三遍。然后才降落。
在Python中,描述了这种行为的模型,然后用清单1中的代码对其进行了仿真。
清单1.蜘蛛平面的Python代码
import asyncio
import time
async def spider(site_name):
for page in range(1, 4):
await asyncio.sleep(1)
print(site_name, page)
spiders = [
asyncio.ensure_future(spider("Blog")),
asyncio.ensure_future(spider("News")),
asyncio.ensure_future(spider("Forum"))
]
start = time.time()
event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(asyncio.gather(*spiders))
event_loop.close()
print("{:.2F}".format(time.time() - start))
这种“飞行”的模拟结果如下:
博客1
新闻1
论坛1
博客2
新闻2
论坛2
博客3
新闻3
论坛3
3.00
为什么视频[1]对此进行了详细解释。但我们球员的想象力和同步(根据场景-异步)的飞行我们三“双雄” ,而无需使用ASYNCIO会-自动挡车型的基础上,提出以不同的方式。例如,清单2显示了自动机延迟的代码,它是asyncio模块的异步延迟的类似物,由清单1中的await asyncio.sleep(1)行表示。
清单2. Python中的自动延迟代码
import time
class PSleep:
def __init__(self, t, p_FSM): self.SetTime = t; self.nState = 0; self.bIfLoop = False; self.p_mainFSM = p_FSM
def x1(self): return time.time() - self.t0 <= self.SetTime
def y1(self): self.t0 = time.time()
def loop(self):
if (self.nState == 0): self.y1(); self.nState = 1
elif (self.nState == 1):
if (not self.x1()): self.nState = 4
延迟值和指向创建延迟对象的对象的指针通过类构造函数传递。流程控制功能需要该指针,该指针在消除延迟后将继续创建时已停止的父流程。
清单3显示了异步蜘蛛平面的自动机副本(另请参见清单1)。即使在最噩梦中,Python编程王牌也很可能不会梦想如此!四行的源代码增长了15倍!这不是一般的Python代码特别是asycio令人钦佩的原因,还是至少证明“协程技术”优于自动机编程的证据?
清单3. Python中自动机蜘蛛的代码
# "" "Blog"
class PBSpider:
def __init__(self, name):
self.nState = 0; self.bIfLoop = True; self.site_name = name; self.page = 1;
self.p_mainFSM = b_sleep;
def x1(self): return self.page < 4
def y1(self):
self.bIfLoop = False; automaton.append(b_sleep);
b_sleep.p_mainFSM = blog
automaton[-1].bIfLoop = True;
automaton[-1].nState = 0
def y2(self): print(self.site_name, self.page)
def y3(self): self.page += 1
def y4(self): self.page = 1
def loop(self):
if (self.x1() and self.nState == 0): self.y1(); self.nState = 1
elif (not self.x1() and self.nState == 0): self.y1(); self.y4(); self.nState = 33
elif (self.nState == 1): self.y2(); self.y3(); self.nState = 0
# "" "News"
class PNSpider:
def __init__(self, name):
self.nState = 0; self.bIfLoop = True; self.site_name = name; self.page = 1;
self.p_mainFSM = n_sleep;
def x1(self): return self.page < 4
def y1(self):
self.bIfLoop = False; automaton.append(n_sleep);
n_sleep.p_mainFSM = news
automaton[-1].bIfLoop = True;
automaton[-1].nState = 0
def y2(self): print(self.site_name, self.page)
def y3(self): self.page += 1
def y4(self): self.page = 1
def loop(self):
if (self.x1() and self.nState == 0): self.y1(); self.nState = 1
elif (not self.x1() and self.nState == 0): self.y1(); self.y4(); self.nState = 33
elif (self.nState == 1): self.y2(); self.y3(); self.nState = 0
# "Forum"
class PFSpider:
def __init__(self, name):
self.nState = 0; self.bIfLoop = True; self.site_name = name; self.page = 1;
self.p_mainFSM = f_sleep;
def x1(self): return self.page < 4
def y1(self):
self.bIfLoop = False; automaton.append(f_sleep);
f_sleep.p_mainFSM = forum
automaton[-1].bIfLoop = True;
automaton[-1].nState = 0
def y2(self): print(self.site_name, self.page)
def y3(self): self.page += 1
def y4(self): self.page = 1
def loop(self):
if (self.x1() and self.nState == 0): self.y1(); self.nState = 1
elif (not self.x1() and self.nState == 0): self.y1(); self.y4(); self.nState = 33
elif (self.nState == 1): self.y2(); self.y3(); self.nState = 0
#
b_sleep = PSleep(1, 0)
n_sleep = PSleep(1, 0)
f_sleep = PSleep(1, 0)
# ""
blog = PBSpider("Blog")
news = PNSpider("News")
forum = PFSpider("Forum")
#
automaton = []
automaton.append(blog);
automaton.append(news);
automaton.append(forum);
start = time.time()
# ( event_loop)
while True:
ind = 0;
while True:
while ind < len(automaton):
if automaton[ind].nState == 4:
automaton[ind].p_mainFSM.bIfLoop = True
automaton.pop(ind)
ind -=1
elif automaton[ind].bIfLoop:
automaton[ind].loop()
elif automaton[ind].nState == 33:
print("{:.2F}".format(time.time() - start))
exit()
ind += 1
ind = 0
这是自动飞行的结果:
新闻1
论坛1
博客1
博客2
新闻2
论坛2
新闻3
论坛3论坛3
博客
3.00
但是-让我们讨论一下。代码大小的增加是由于Python中的指针问题所致。结果,我必须为每个页面创建一个类,这使代码增加了两倍。因此,说不多于15个,而是使音量增加大约5倍是正确的。编程中比较熟练的“ Python飞行员”甚至可以消除这一缺点。
但是主要原因仍然不是指针。下面显示的C ++代码具有完全的自由使用指针的功能,每个类具有更多的行。原因是使用了计算模型,描述语言以及基于该模型的算法实现方法。数字:图1以框图形式示出了传统的蜘蛛平面模型和自动机模型。您可以看到,尽管它们允许等效转换,但从外观上和质量上来说,它们是不同的模型。自动机具有状态,但是框图甚至都没有它们的踪迹。根据定义,自动机是在离散时间内运行的,而框图甚至都没有实现这一梦想。所有这些都对模型的实施施加了某些义务。
缺少离散时间的概念是现有块图编程模型的问题的本质,严格地说,该模型必须意识到它无法实现的功能,即 并行过程。回想一下,对于自动机,自动机网络是其并行状态(以及异步过程)的模型,是其自然状态。
数字:1.蜘蛛平面的自动模型和方框图模型
但是,即使在一个单独的流程级别上,模型也会有差异,这些差异会投射到模型的语言和实现上。凭借这些品质,一致框图的辩护者已经创建了语言构造,无论是显式的还是隐式的,都可以非常紧凑地对其进行描述。采取相同的for循环或至少隐式执行操作符的顺序(动作y1,y2,y3)。
对于流程图,您可以在一个框中列出操作而不会出现任何问题,并且这不会改变其工作的顺序性质。如果自动机用状态s1中的循环替换状态s2,s3中的过渡,并用相同的动作标记弧,则算法的含义将改变,因为将在其工作中引入并行性。由于必须严格顺序地执行上述动作,因此预先确定了自动机模型的外观(见图1)。有限自动机是不允许“双重思考”的模型。
框图中缺少离散时间是它们的优势。但是现在这已成为他们的主要缺点。它似乎似乎没有亵渎神灵地影响着思维方式。顺序语言通过拒绝其他东西-并行来证明程序员的顺序思维。这证明了现有异步编程的构造是正确的,并提供了相同asyncio包的运算符的集合和功能。有人认为,正是这种方法允许程序员将他们熟悉的顺序程序转换为异步(几乎并行)程序。
但是回到文章的主题及其图像。我们想要我们的“飞机”,我们做到了!飞行,或更确切地说,它们的可见结果,在外观上有所不同,但在本质上却完全无法区分。可以以这样一种方式来解释它们,即以不同的顺序选择并记录协议中的标志,但是“平面”本身会按原样飞行,即同时并同时扔出自己的旗帜。并以什么顺序进行记录-如他们所说,情况是第十。最主要的事情已经实现并完成:下降的顺序和时间与飞行程序相对应
可以缩短代码。因此,显然,您可以将自己限制为仅一类的代码。您还可以隐藏事件循环代码。如果同时在源代码中打开隐藏在asyncio和await运算符后面的引擎舱代码,则自动机代码的数量很可能不会那么吓人。
3.关于在Python中实现自动机的问题
让我们更详细地讨论引起自动代码出现的问题。与源代码相比,隐藏在这里的最后一件事看起来如此可怕。但是,让我们注意到,莫扎伊斯基的第一架飞机与现代“干燥”飞机相去甚远,而且第一批汽车与现代飞机相比并没有什么不同。让我强调一下,提出的自动机代码的问题在很大程度上与我目前对Python语言的理解有关,也许在某种程度上与语言本身的功能有关。
然而,第一个问题与自动机模型的描述语言有关。在C ++中,它是通过语言解决的。我在Python中看不到这种可能性。不幸的是,正如他们现在有时所说的那样,从根本上来说。因此,以基于if-elif-else语言的控制算子实现自动机的方法为基础。此外,我们还记得在CPSU(a)中,除了自动机本身之外,还引入了影子内存和自动机空间以完全实现并行性。没有这一点,自动机编程的可能性就非常有限,并且在许多方面都差强人意。
我们已经提到的下一个问题是指针。在C ++中,它们没有问题。在CPSU(a)的框架内,根据OOP范例,创建了一个基本自动机类,从中生成了应用的自动机类,它们的参数不仅可以是指针,甚至可以是它们的地址。所有这些使得有可能简单,紧凑且非常有效地描述和实施包括许多并行交互过程的任何任务。
以下是等效于所考虑示例的C ++自动机类的代码。清单4中的延迟代码等效于清单1中的await asyncio.sleep(1)行。以图形形式,它对应于图1中的FAwaitSleep自动机模型。1.这样的自动机可以被认为是异步的,并且不会减慢计算流程。同一图中的FSleep对应于通常的sleep()运算符。它比较简单,但是由于y1的作用导致通常的顺序延迟,因此可以保证破坏离散时间模型。这对任何事物都不再有用。
清单4.异步延迟代码
// ( )
#include "lfsaappl.h"
#include <QTime>
class FAwaitSleep :
public LFsaAppl
{
public:
FAwaitSleep(int n);
protected:
int x1();
QTime time;
int nAwaitSleep;
};
#include "stdafx.h"
#include "FAwaitSleep.h"
static LArc TBL_AwaitSleep[] = {
LArc("s1", "s1","x1", "--"), //
LArc("s1", "00","^x1", "--"), //
LArc()
};
FAwaitSleep::FAwaitSleep(int n):
LFsaAppl(TBL_AwaitSleep, "FAwaitSleep")
{
nAwaitSleep = n; time.start();
}
int FAwaitSleep::x1() { return time.elapsed() < nAwaitSleep; }
清单5中显示了蜘蛛平面的C ++代码。与Python代码的框图相比,此代码对其模型更为合适。特别是如果我们比较自动机的过渡表和自动机图的外观。它们只是描述同一抽象概念(自动机)的不同形式。它还显示了创建延迟时如何传递指向父类的指针(请参见活动y1中对FCall方法的调用)
清单5.模拟阅读站点页面的蜘蛛平面的代码
// "".
#include "lfsaappl.h"
class FAwaitSleep;
class FSpider :
public LFsaAppl
{
public:
LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FSpider(nameFsa); }
bool FCreationOfLinksForVariables() override;
FSpider(string strNam);
virtual ~FSpider(void);
CVar *pVarStrSiteName; //
FAwaitSleep *pFAwaitSleep{nullptr};
protected:
int x1(); void y1(); void y2(); void y3(); void y4();
int page{1};
};
#include "stdafx.h"
#include "FSpider.h"
#include "FSleep.h"
#include "FAwaitSleep.h"
#include <QDebug>
static LArc TBL_Spider[] = {
LArc("st","s1","--","--"),
LArc("s1","s2","x1","y1"), // x1- <. ; y1-;
LArc("s2","s3","--","y2"), // y2- ;
LArc("s3","s1","--","y3"), // y3-
LArc("s1","st","^x1","y4"), // y4-
LArc()
};
FSpider::FSpider(string strNam):
LFsaAppl(TBL_Spider, strNam)
{ }
FSpider::~FSpider(void) { if (pFAwaitSleep) delete pFAwaitSleep; }
bool FSpider::FCreationOfLinksForVariables() {
pVarStrSiteName = CreateLocVar("strSiteName", CLocVar::vtString, "name of site");
return true;
}
// ?
int FSpider::x1() { return page < 4; }
// create delay - pure sleep (synchronous function) or await sleep (asynchronous function)
void FSpider::y1() {
//sleep(1000);
// await sleep (asynchronous function)
if (pFAwaitSleep) delete pFAwaitSleep;
pFAwaitSleep = new FAwaitSleep(1000);
pFAwaitSleep->FCall(this);
}
void FSpider::y2() {
#ifdef QT_DEBUG
string str = pVarStrSiteName->strGetDataSrc();
printf("%s%d", str.c_str(), page);
qDebug()<<str.c_str()<<page;
#endif
}
void FSpider::y3() { page++; }
void FSpider::y4() { page = 1; }
没有代码可以实现所谓的事件循环的功能。完全没有必要。它的功能由CPSU(a)环境的核心执行。它创建对象并在离散时间内管理它们的并行执行。
4。结论
精简并不总是人才的姊妹,有时它也是言不由衷的标志。没错,很难一次将彼此区分开。 Python代码通常比C ++代码短。但这是简单情况下的典型情况。解决方案越复杂,这种差异就越小。最后,甚至解决方案的复杂性也取决于模型的功能。自动机模型比框图强大得多。
首先,自动机和并行化是解决复杂性问题,与之抗衡的非常有效的方法,而并不是提高程序速度的一种方法。由于所有这些都是自动机模型,因此并行性很难在Python中实现,因此,尽管它具有所有的芯片,电池和更多其他功能,但我却很难向其方向发展。我会更多地关注C ++环境,而不是在其中引入相同的协程。该模型是临时的,实施该模型的原因在很大程度上是强制性的。解决并行模型选择问题后,我们将如何处理这个“拐杖”?
因此,很抱歉,但我的偏好仍然是C ++。而且如果您考虑我专业兴趣的领域-所谓的``令人毛骨悚然''的实时工业系统,那么我别无选择。是的,可以使用Python创建某种环境和某种服务。它方便,快速,有很多原型,等等。等等但是,解决方案的核心,并行模型,流程本身的逻辑无疑是C ++,无疑是自动机。当然,在这里自动机更为重要和规则。但不是协程:)
另外...请观看视频[2],注意火箭模型的实现。关于她的视频从第12分钟开始讲述。尊重使用机器的讲师:)还有一种甜蜜的享受,这是[3]中的另一种解决方案... 本着异步编程和异步的精神。实际上,这一切都始于该示例-Python中嵌套自动机的实现。此处的嵌套深度甚至比上述示例中的嵌套深度还要大。清单6显示了源代码及其对应的Python自动机。在图。图2是自动饮茶模型,清单7显示了VKP的等效C ++实现(a)。比较,分析,得出结论,批评...
清单6.用Python异步读取和喝茶
import asyncio
import time
# # Easy Python. Asyncio python 3.7 https://www.youtube.com/watch?v=PaY-hiuE5iE
# # 10:10
# async def teatime():
# await asyncio.sleep(1)
# print('take a cap of tea')
# await asyncio.sleep(1)
#
# async def read():
# print('Reading for 1 hour...')
# await teatime()
# print('...reading for 1 hour...')
#
# if __name__ == '__main__':
# asyncio.run(read())
class PSleep:
def __init__(self, t, p_FSM): self.SetTime = t; self.nState = 0; self.bIfLoop = False; self.p_mainFSM = p_FSM
def x1(self): return time.time() - self.t0 <= self.SetTime
def y1(self): self.t0 = time.time()
def loop(self):
if (self.nState == 0): self.y1(); self.nState = 1
elif (self.nState == 1):
if (not self.x1()): self.nState = 4
class PTeaTime:
def __init__(self, p_FSM): self.nState = 0; self.bIfLoop = False; self.p_mainFSM = p_FSM;
def y1(self): self.bIfLoop = False; automaton.append(sl); automaton[-1].bIfLoop = True; automaton[-1].nState = 0
def y2(self): print('take a cap of tea')
def loop(self):
if (self.nState == 0): self.y1(); self.nState = 1
elif (self.nState == 1): self.y2(); self.nState = 2
elif (self.nState == 2): self.y1(); self.nState = 3
elif (self.nState == 3): self.nState = 4
class PRead:
def __init__(self): self.nState = 0; self.bIfLoop = False;
def y1(self): print('Reading for 1 hour...')
def y2(self): self.bIfLoop = False; automaton.append(rt); automaton[-1].bIfLoop = True; automaton[-1].nState = 0
def loop(self):
if (self.nState == 0): self.y1(); self.nState = 1
elif (self.nState == 1): self.y2(); self.nState = 2
elif (self.nState == 2): self.y1(); self.nState = 33; self.bIfLoop = False
read = PRead()
rt = PTeaTime(read)
sl = PSleep(5, rt)
automaton = []
automaton.append(read); automaton[-1].bIfLoop = True
while True:
ind = 0;
while True:
while ind < len(automaton):
if automaton[ind].nState == 4:
automaton[ind].p_mainFSM.bIfLoop = True
automaton.pop(ind)
ind -=1
elif automaton[ind].bIfLoop:
automaton[ind].loop()
elif automaton[ind].nState == 33:
exit()
ind += 1
ind = 0
数字:2.自动饮茶模型
清单7.用C ++异步阅读和喝茶
#include "lfsaappl.h"
class FRead :
public LFsaAppl
{
public:
LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FRead(nameFsa); }
FRead(string strNam);
virtual ~FRead(void);
protected:
void y1(); void y2(); void y3();
LFsaAppl *pFRealTime{nullptr};
};
#include "stdafx.h"
#include "FRead.h"
#include "FTeaTime.h"
#include <QDebug>
static LArc TBL_Read[] = {
LArc("s1","s2","--","y1"), // Reading for 1 hour...
LArc("s2","s3","--","y2"), // Call(TeaTime)
LArc("s3","s4","--","y1"), // Reading for 1 hour...
LArc("s4","s5","--","y3"), // sleep(5)
LArc("s5","s1","--","--"), //
LArc()
};
FRead::FRead(string strNam):
LFsaAppl(TBL_Read, strNam)
{ }
FRead::~FRead(void) { if (pFRealTime) delete pFRealTime; }
void FRead::y1() {
#ifdef QT_DEBUG
qDebug()<<"Reading for 1 hour...";
#endif
}
void FRead::y2() {
if (pFRealTime) delete pFRealTime;
pFRealTime = new FTeaTime("TeaTime");
pFRealTime->FCall(this);
}
void FRead::y3() { FCreateDelay(5000); }
#include "lfsaappl.h"
class FTeaTime :
public LFsaAppl
{
public:
FTeaTime(string strNam);
protected:
void y1(); void y2();
};
#include "stdafx.h"
#include "FTeaTime.h"
#include <QDebug>
#include "./LSYSLIB/FDelay.h"
static LArc TBL_TeaTime[] = {
LArc("s1", "s2","--","y1"),// sleep(1)
LArc("s2", "s3","--","y2"),// take a cap of tea
LArc("s3", "s4","--","y1"),// sleep(1)
LArc("s4", "00","--","--"),//
LArc()
};
FTeaTime::FTeaTime(string strNam):
LFsaAppl(TBL_TeaTime, strNam)
{ }
void FTeaTime::y1() { FCreateDelay(2000); }
void FTeaTime::y2() {
#ifdef QT_DEBUG
qDebug()<<"take a cap of tea";
#endif
}
聚苯乙烯
在写完这篇文章之后,在阅读了Yerain Diaz [4]的文章翻译之后,我熟悉了另一种相当有趣和令人钦佩的外观,特别是关于协程,特别是异步。尽管有这个事实和其他类似的看法,我们仍将“另辟go径” :)我只同意Rob Pike的一件事,即“并发不是无关紧要”。竞争力甚至可以说更强硬,与并行性完全无关。值得注意的是Google Translate将此短语翻译为“并行不是并行”。这个名叫Google的人肯定是错的。但是有人说服他呢?:)
文学
- Shultais Education. 1. . [ ], : www.youtube.com/watch?v=BmOjeVM0w1U&list=PLJcqk6mrJtxCo_KqHV2rM2_a3Z8qoE5Gk, . . . ( 01.08.2020).
- Computer Science Center. 9. async / await ( Python). [ ], : www.youtube.com/watch?v=x6JZmBK2I8Y, . . . ( 13.07.2020).
- Easy Python. Asyncio python 3.7. [ ], : www.youtube.com/watch?v=PaY-hiuE5iE, . . . ( 01.08.2020).
- Yeray Diaz。面向python开发者的Asyncio。[电子资源],访问模式:www.youtube.com/watch?v=PaY-hiuE5iE,免费。语言。俄语 (治疗日期08/01/2020)。