التزامن ، coroutines ، آلات الحدث ، ... الرياضيات الحية

تبهر الحوسبة المتوازية بسلوكها غير المتوقع. لكن السلوك المشترك للعمليات لا يمكن التنبؤ به. فقط في هذه الحالة يمكن دراسته وفهمه في المراوغات. التزامن الحديث متعدد الخيوط فريد من نوعه. بالمعنى الحرفي. وهذا هو جوهره السيئ . الجوهر الذي يمكن ويجب أن يتأثر. الجوهر ، الذي كان ينبغي ، بطريقة جيدة ، أن يتغير منذ فترة طويلة ... على

الرغم من وجود خيار آخر. ليست هناك حاجة لتغيير أي شيء و / أو التأثير على شيء ما. يجب ألا يكون هناك تعدد مؤشرات و corotines ، فليكن ... والبرمجة التلقائية المتوازية (AP). دعهم يتنافسون ويكملوا بعضهم البعض عند الضرورة. وبهذا المعنى ، فإن التوازي الحديث له ميزة واحدة على الأقل - فهو يسمح لك بذلك.

حسنا ، دعونا نتنافس !؟

1. من المسلسل إلى المتوازي


خذ بعين الاعتبار برمجة أبسط معادلة حسابية:

C2 = A + B + A1 + B1 ؛ (1)

يجب أن تكون هناك كتل تنفذ عمليات حسابية بسيطة. في هذه الحالة ، كتل التلخيص كافية. تعطي فكرة واضحة ودقيقة عن عدد الكتل وهيكلها والعلاقات بينها الأرز. 1. وفي الشكل 2. يتم تكوين وسط VKP (a) لحل المعادلة (1).

صورة
رسم بياني 1. النموذج الهيكلي للعمليات

لكن الرسم الهيكلي في الشكل 1 يتوافق مع نظام من ثلاث معادلات:

= A + B ؛
C1 = A1 + B ؛ (2)
C2 = C + C1 ؛

في نفس الوقت (2) ، هذا هو تنفيذ موازي للمعادلة (1) ، وهي خوارزمية لجمع مجموعة من الأرقام ، والمعروفة أيضًا باسم خوارزمية المضاعفة. يتم تمثيل المصفوفة هنا بأربعة أرقام A ، B ، A1 ، B1 ، المتغيرات C و C1 هي نتائج وسيطة ، و C2 هي مجموع المصفوفة.

صورة
الصورة 2. نوع مربعات الحوار لتكوين ثلاث عمليات متوازية ،

وتشمل ميزات التنفيذ استمرارية تشغيلها ، عندما يؤدي أي تغيير في بيانات الإدخال إلى إعادة فرز النتيجة. بعد تغيير بيانات الإدخال ، سيستغرق الأمر دورتين للساعة ، وعندما يتم توصيل الكتل في سلسلة ، سيتم تحقيق نفس التأثير في ثلاث دورات للساعة. وكلما كبرت المجموعة ، زادت مكاسب السرعة.

2. التزامن كمشكلة


لا تتفاجأ إذا تم استدعاؤك إلى العديد من الحجج لصالح حل موازٍ أو آخر ، ولكن في نفس الوقت سيكونون صامتين بشأن المشكلات المحتملة التي تكون غائبة تمامًا في البرمجة التسلسلية العادية. السبب الرئيسي لتفسير مماثل لمشكلة التنفيذ الصحيح للتوازي. يقولون أقل شيء عنها. إذا قالوا على الإطلاق. سنتطرق إليها في الجزء المتعلق بالوصول الموازي للبيانات.

يمكن تمثيل أي عملية على أنها خطوات متتالية غير قابلة للتجزئة. بالنسبة للعديد من العمليات ، في كل خطوة من هذا القبيل ، يتم تنفيذ الإجراءات التي تنتمي إلى جميع العمليات في وقت واحد. وقد نواجه هنا مشكلة تتجلى في المثال الأولي التالي.

افترض أن هناك عمليتين متوازيتين تتوافقان مع نظام المعادلات التالي:

ج = أ + ب ؛ (3)
أ = ب + ج ؛

لنفترض أن المتغيرات أ ، ب ، ج تم تعيين القيم الأولية 1 ، 1 ، 0. يمكننا أن نتوقع أن بروتوكول الحساب للخطوات الخمس سيكون على النحو التالي:

a              b               c
1.000       1.000       0.000      
1.000       1.000       2.000       
3.000       1.000       2.000       
3.000       1.000       4.000       
5.000       1.000       4.000        
5.000       1.000       6.000   

عند تشكيلها ، انطلقنا من حقيقة أن العوامل يتم تنفيذها بالتوازي (في نفس الوقت) وضمن مقياس منفصل (خطوة). للعبارات المكررة ، سيكون تكرارًا للحلقة. يمكننا أيضًا أن نفترض أنه في عملية الحسابات ، تكون للمتغيرات قيم ثابتة في بداية مقياس منفصل ، وتغييرها يحدث في نهايته. هذا يتفق تمامًا مع الوضع الحقيقي ، عندما يستغرق الأمر بعض الوقت لإكمال العملية. غالبًا ما يرتبط بالتأخير المتأصل في كتلة معينة.

ولكن ، على الأرجح ، ستحصل على شيء مثل هذا البروتوكول:

   a              b               c
1.000       1.000       0.000      
3.000       1.000       2.000       
5.000       1.000       4.000       
7.000       1.000       6.000       
9.000       1.000       8.000       
11.000     1.000     10.000       

وهو يعادل عمل عملية تنفيذ عبارتين متتاليتين في دورة:

c = a + b؛ أ = ب + ج ؛ (4)

ولكن قد يحدث أن تنفيذ البيانات سيكون عكس ذلك تمامًا ، وبعد ذلك سيكون البروتوكول على النحو التالي:

   a              b               c
1.000       1.000       0.000      
1.000       1.000       2.000       
3.000       1.000       4.000       
5.000       1.000       6.000       
7.000       1.000       8.000       
9.000       1.000     10.000       

في البرمجة متعددة الخيوط ، يكون الوضع أسوأ. في غياب مزامنة العمليات ، ليس من الصعب فقط توقع تسلسل إطلاق المشغلين ، ولكن سيتم أيضًا إيقاف عملهم في أي مكان. كل هذا لا يمكن إلا أن يؤثر على نتائج العمل المشترك للمشغلين.

في إطار تقنية AP ، يُسمح بالعمل مع متغيرات العملية الشائعة ببساطة وبشكل صحيح. هنا ، في معظم الأحيان ، لا يلزم بذل جهود خاصة لمزامنة العمليات والعمل مع البيانات. ولكن سيكون من الضروري تحديد الإجراءات التي سيتم اعتبارها فورية مشروطة وغير قابلة للتجزئة ، بالإضافة إلى إنشاء نماذج معالجة تلقائية. في حالتنا ، ستكون الإجراءات مشغلي الجمع ، وستكون الأوتوماتا ذات التحولات الدورية مسؤولة عن إطلاقها.
تعرض القائمة 1 رمز العملية التي تنفذ عملية المجموع. نموذجها عبارة عن آلة حالة محدودة (انظر الشكل 3) مع حالة واحدة وانتقال حلقة غير مشروطة ، حيث يؤدي الإجراء الوحيد y1 ، بعد إجراء عملية جمع متغيرين ، إلى وضع النتيجة في الثالث.

صورة
تين. 3. نموذج آلي لعملية الجمع

قائمة 1. تنفيذ عملية الأوتوماتيكية لعملية المبلغ
#include "lfsaappl.h"
class FSumABC :
    public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FSumABC(nameFsa); }
    bool FCreationOfLinksForVariables();
    FSumABC(string strNam);
    CVar *pVarA;		//
    CVar *pVarB;		//
    CVar *pVarC;		//
    CVar *pVarStrNameA;        //
    CVar *pVarStrNameB;        //
    CVar *pVarStrNameC;        //
protected:
    void y1();
};

#include "stdafx.h"
#include "FSumABC.h"

static LArc TBL_SumABC[] = {
    LArc("s1",	"s1","--", "y1"),
    LArc()
};

FSumABC::FSumABC(string strNam):
    LFsaAppl(TBL_SumABC, strNam, nullptr, nullptr)
{ }

bool FSumABC::FCreationOfLinksForVariables() {
    pVarA = CreateLocVar("a", CLocVar::vtBool, "variable a");
    pVarB = CreateLocVar("b", CLocVar::vtBool, "variable c");
    pVarC = CreateLocVar("c", CLocVar::vtBool, "variable c");
    pVarStrNameA = CreateLocVar("strNameA", CLocVar::vtString, "");
    string str = pVarStrNameA->strGetDataSrc();
    if (str != "") { pVarA = pTAppCore->GetAddressVar(pVarStrNameA->strGetDataSrc().c_str(), this); }
    pVarStrNameB = CreateLocVar("strNameB", CLocVar::vtString, "");
    str = pVarStrNameB->strGetDataSrc();
    if (str != "") { pVarB = pTAppCore->GetAddressVar(pVarStrNameB->strGetDataSrc().c_str(), this); }
    pVarStrNameC = CreateLocVar("strNameC", CLocVar::vtString, "");
    str = pVarStrNameC->strGetDataSrc();
    if (str != "") { pVarC = pTAppCore->GetAddressVar(pVarStrNameC->strGetDataSrc().c_str(), this); }
    return true;
}

void FSumABC::y1() { 
    pVarC->SetDataSrc(this, pVarA->GetDataSrc() + pVarB->GetDataSrc()); 
}


المهم ، أو بالأحرى ، حتى ضروري ، هنا استخدام متغيرات البيئة في CPSU. تضمن "خصائص الظل" الخاصة بهم التفاعل الصحيح للعمليات. علاوة على ذلك ، تسمح لك البيئة بتغيير وضع عملها ، باستثناء تسجيل المتغيرات في ذاكرة الظل المتوسطة. يسمح لنا تحليل البروتوكولات التي تم الحصول عليها في هذا الوضع بالتحقق من ضرورة استخدام متغيرات الظل.

3. و coroutines؟ ...


سيكون من اللطيف معرفة كيف ستتعامل coroutines التي تمثلها لغة Kotlin مع المهمة. لنأخذ كنموذج حل البرنامج الذي تم تناوله في مناقشة [1]. لديها هيكل يمكن اختزاله بسهولة إلى المظهر المطلوب. للقيام بذلك ، استبدل المتغيرات المنطقية فيه بنوع رقمي وأضف متغيرًا آخرًا ، وبدلاً من العمليات المنطقية ، سنستخدم عملية الجمع. يظهر الرمز المقابل في القائمة 2.

القائمة 2. برنامج الجمع المتوازي Kotlin
import kotlinx.coroutines.*

suspend fun main() =
    // Structured concurrency: if any child coroutine fails,
    // everything else will be cancelled
    coroutineScope {
        var a = 1
        var b = 1
        var c = 0;
        // Use default thread pool 
        withContext(Dispatchers.Default) {
            for (i in 0..4) {
               var res = listOf(async { a+b }, async{ b+c }).map { it.await() }
			c = res[0]
			a = res[1]
               println("$a, $b, $c")
            }
        }
    }


لا توجد أسئلة حول نتيجة هذا البرنامج ، مثل يطابق تمامًا أول البروتوكولات أعلاه.

ومع ذلك ، لم يكن تحويل شفرة المصدر واضحًا كما قد يبدو ، لأنه يبدو من الطبيعي استخدام جزء التعليمات البرمجية التالي:

listOf(async {  = a+b }, async{  = b+c })

كما هو موضح من خلال الاختبار (يمكن القيام بذلك عبر الإنترنت على موقع Kotlin - kotlinlang.org/#try-kotlin ) ، يؤدي استخدامه إلى نتيجة غير متوقعة تمامًا ، والتي تتغير أيضًا من الإطلاق إلى الإطلاق. وأدى تحليل أكثر دقة للبرنامج المصدر فقط إلى الكود الصحيح.

الكود الذي يحتوي على خطأ من وجهة نظر أداء البرنامج ، لكنه شرعي من وجهة نظر اللغة ، يجعلنا نخشى على موثوقية البرامج عليه. هذا الرأي ، ربما ، يمكن الطعن فيه من قبل خبراء Kotlin. ومع ذلك ، فإن سهولة ارتكاب خطأ ، والذي لا يمكن تفسيره إلا من خلال عدم فهم "برمجة coroutine" ، مع ذلك ، تدفع باستمرار من أجل هذه الاستنتاجات.

4. آلات الحدث في كيو تي


في وقت سابق ، أثبتنا أن الحدث الآلي ليس آليًا في تعريفه الكلاسيكي. إنه جيد أو سيئ ، ولكن إلى حد ما ، آلة الحدث لا تزال قريبة من الآلات الكلاسيكية. هل هو بعيد ، قريب ، ولكن يجب أن نتحدث عنه مباشرة حتى لا تكون هناك مفاهيم خاطئة حول هذا الموضوع. بدأنا نتحدث عن هذا في [2] ، ولكن كل ذلك لمواصلة ذلك. الآن سنفعل ذلك من خلال فحص أمثلة أخرى لاستخدام آلات الأحداث في Qt.

بالطبع ، يمكن اعتبار الحدث الآلي كحالة متدهورة للآلة الكلاسيكية ذات مدة دورة غير محددة و / أو متغيرة مرتبطة بحدث. تم توضيح إمكانية مثل هذا التفسير في مقال سابق عند حل واحد فقط ، علاوة على ذلك ، مثال محدد إلى حد ما (انظر التفاصيل [2]). بعد ذلك ، سنحاول إزالة هذه الفجوة.

لا تربط مكتبة Qt إلا التحولات الآلية بالأحداث ، وهو قيد خطير. على سبيل المثال ، في نفس لغة UML ، لا يرتبط الانتقال فقط بحدث يسمى حدث البدء ، ولكن أيضًا بشرط وقائي - تعبير منطقي محسوب بعد استلام الحدث [3]. في MATLAB ، يتم تخفيف الموقف بشكل أكبر ويبدو كالتالي: "إذا لم يتم تحديد اسم الحدث ، فسيحدث الانتقال عند حدوث أي حدث" [4]. ولكن هنا وهناك ، فإن السبب الجذري للانتقال هو الحدث / الأحداث. ولكن ماذا لو لم تكن هناك أحداث؟

إذا لم تكن هناك أحداث ، فعندئذٍ ... يمكنك محاولة إنشائها. قائمة 3 والشكل 4 شرح كيفية القيام بذلك ، باستخدام سليل فئة automaton LFsaAppl لبيئة VKPa كـ "غلاف" لحدث Qt-class. هنا ، يرسل الإجراء y2 مع تواتر الوقت المنفصل لمساحة الأوتوماتي إشارة تبدأ بدء انتقال Qt automaton. يبدأ الأخير ، باستخدام طريقة s0Exited ، الإجراء y1 ، الذي ينفذ عملية الجمع. لاحظ أن آلة الحدث تم إنشاؤها بواسطة الإجراء y3 بدقة بعد التحقق من تهيئة المتغيرات المحلية لفئة LFsaAppl.

صورة
الشكل 4. مزيج من الآلات الكلاسيكية والفعاليات

قائمة 3. تنفيذ نموذج تجميع مع حدث آلي
#include "lfsaappl.h"
class QStateMachine;
class QState;

class FSumABC :
    public QObject,
    public LFsaAppl
{
    Q_OBJECT
...
protected:
    int x1();
    void y1(); void y2(); void y3(); void y12();
signals:
    void GoState();
private slots:
    void s0Exited();
private:
    QStateMachine * machine;
    QState * s0;
};

#include "stdafx.h"
#include "FSumABC.h"
#include <QStateMachine>
#include <QState>

static LArc TBL_SumABC[] = {
    LArc("st",	"st","^x1",	"y12"),
    LArc("st",	"s1","x1",	"y3"),
    LArc("s1",	"s1","--",	"y2"),
    LArc()
};

FSumABC::FSumABC(string strNam):
    QObject(),
    LFsaAppl(TBL_SumABC, strNam, nullptr, nullptr)
{ }
...
int FSumABC::x1() { return pVarA&&pVarB&&pVarC; }

void FSumABC::y1() {
    pVarC->SetDataSrc(this, pVarA->GetDataSrc() + pVarB->GetDataSrc());
}
//
void FSumABC::y2() { emit GoState(); }
//
void FSumABC::y3() {
    s0 = new QState();
    QSignalTransition *ps = s0->addTransition(this, SIGNAL(GoState()), s0);
    connect (s0, SIGNAL(entered()), this, SLOT(s0Exited()));
    machine = new QStateMachine(nullptr);
    machine->addState(s0);
    machine->setInitialState(s0);
    machine->start();
}
//    
void FSumABC::y12() { FInit(); }

void FSumABC::s0Exited() { y1(); }


أعلاه ، قمنا بتنفيذ آلة بسيطة للغاية. أو ، بشكل أدق ، مزيج من الأوتوماتيكية الكلاسيكية والأحداث. إذا تم استبدال التطبيق السابق لفئة FSumABC بالفئة التي تم إنشاؤها ، فلن يكون هناك ببساطة اختلافات في التطبيق. ولكن بالنسبة إلى النماذج الأكثر تعقيدًا ، تبدأ الخصائص المحدودة للأتمتة التي يحركها الحدث في الظهور بشكل كامل. كحد أدنى ، بالفعل في عملية إنشاء نموذج. تظهر القائمة 4 تنفيذ نموذج عنصر AND-NOT في شكل حدث آلي (لمزيد من التفاصيل حول نموذج التشغيل الآلي للعنصر AND-NOT ، انظر [2]).

قائمة 4. تنفيذ نموذج عنصر وليس بواسطة آلة الحدث
#include <QObject>

class QStateMachine;
class QState;

class MainWindow;
class ine : public QObject
{
    Q_OBJECT
public:
    explicit ine(MainWindow *parent = nullptr);
    bool bX1, bX2, bY;
signals:
    void GoS0();
    void GoS1();
private slots:
    void s1Exited();
    void s0Exited();
private:
    QStateMachine * machine;
    QState * s0;
    QState * s1;
    MainWindow *pMain{nullptr};
friend class MainWindow;
};

#include "ine.h"
#include <QStateMachine>
#include <QState>
#include "mainwindow.h"
#include "ui_mainwindow.h"

ine::ine(MainWindow *parent) :
    QObject(parent)
{
    pMain = parent;
    s0 = new QState();
    s1 = new QState();

    s0->addTransition(this, SIGNAL(GoS1()), s1);
    s1->addTransition(this, SIGNAL(GoS0()), s0);

    connect (s0, SIGNAL(entered()), this, SLOT(s0Exited()));
    connect (s1, SIGNAL(entered()), this, SLOT(s1Exited()));


    machine = new QStateMachine(nullptr);
    machine->addState(s0);
    machine->addState(s1);
    machine->setInitialState(s1);
    machine->start();
}

void ine::s1Exited() {
    bY = !(bX1&&bX2);
    pMain->ui->checkBoxY->setChecked(bY);
}

void ine::s0Exited() {
    bY = !(bX1&&bX2);
    pMain->ui->checkBoxY->setChecked(bY);
}


يصبح من الواضح أن أوتوماتا الحدث في Qt تستند بشكل صارم إلى Moore automata. هذا يحد من قدرات ومرونة النموذج ، كما ترتبط الإجراءات فقط مع الدول. ونتيجة لذلك ، على سبيل المثال ، من المستحيل التمييز بين انتقالين من حالة 0 إلى 1 للأوتوماتون الموضح في الشكل. 4 في [2].

بالطبع ، لتطبيق الأميال ، يمكنك استخدام الإجراء المعروف للتبديل إلى أجهزة Moore. لكن هذا يؤدي إلى زيادة في عدد الحالات ويزيل الارتباط البسيط والمرئي والمفيد بين الحالات النموذجية نتيجة أفعالها. على سبيل المثال ، بعد مثل هذه التحولات ، يجب أن تتطابق حالتا Moore automaton مع الحالة الفردية لمخرج النموذج 1 من [2].

في نموذج أكثر تعقيدًا ، تبدأ مشاكل ظروف الانتقال في الظهور بوضوح. للتغلب عليها لتنفيذ البرنامج للعنصر AND-NOT قيد النظر ، تم تضمين تحليل لحالة قنوات الإدخال في مربع حوار التحكم في النموذج ، كما هو موضح في القائمة 5.

القائمة 5. مربع حوار التحكم بعنصر NAND
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ine.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    pine = new ine(this);
    connect(this, SIGNAL(GoState0()), pine, SIGNAL(GoS0()));
    connect(this, SIGNAL(GoState1()), pine, SIGNAL(GoS1()));
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_checkBoxX1_clicked(bool checked)
{
    bX1 = checked;
    pine->bX1 = bX1;
    bY = !(bX1&&bX2);
    if (!(bX1&&bX2)) emit GoState0();
    else emit GoState1();
}

void MainWindow::on_checkBoxX2_clicked(bool checked)
{
    bX2 = checked;
    pine->bX2 = bX2;
    bY = !(bX1&&bX2);
    if (!(bX1&&bX2)) emit GoState0();
    else emit GoState1();
}


باختصار ، كل ما سبق يعقّد النموذج ويخلق مشاكل في فهم عمله. بالإضافة إلى ذلك ، قد لا تعمل هذه الحلول المحلية عند النظر في التراكيب منها. مثال جيد في هذه الحالة هو محاولة إنشاء نموذج RS- الزناد (لمزيد من التفاصيل حول نموذج آلي مكون من مكونين من الزناد RS انظر [5]). ومع ذلك ، سيتم تسليم متعة النتيجة المحققة لمحبي آلات الحدث. إذا ... ما لم ينجحوا بالطبع ؛)

5. وظيفة تربيعية و ... فراشة؟


من الملائم تمثيل بيانات الإدخال كعملية موازية خارجية. وفوق ذلك كان مربع الحوار لإدارة نموذج عنصر AND-NOT. علاوة على ذلك ، يمكن أن يؤثر معدل تغيير البيانات بشكل كبير على النتيجة. لتأكيد ذلك ، نأخذ في الاعتبار حساب الدالة التربيعية y = ax² + bx + c ، والتي ننفذها في شكل مجموعة من الكتل المتوازية والمتفاعلة.

من المعروف أن الرسم البياني للدالة التربيعية له شكل القطع المكافئ. لكن القطع المكافئ الذي يصوره عالم الرياضيات والقطع المكافئ الذي سيعرضه راسم الذبذبات ، على سبيل المثال ، لن يتطابق أبدًا. والسبب في ذلك هو أن عالم الرياضيات غالبًا ما يفكر في الفئات الآنية ، معتقدًا أن التغيير في كمية المدخلات يؤدي على الفور إلى حساب الوظيفة. لكن في الحياة الواقعية ، هذا ليس صحيحًا على الإطلاق. سيعتمد مظهر الرسم البياني للدالة على سرعة الآلة الحاسبة ومعدل تغير بيانات الإدخال وما إلى ذلك. إلخ نعم ، وقد تختلف البرامج نفسها للسرعة عن بعضها البعض. ستؤثر هذه العوامل على شكل الوظيفة ، والتي سيكون من الصعب في شكلها في حالة معينة تخمين القطع المكافئ. سنكون مقتنعين بهذا أكثر.

لذلك ، نضيف إلى كتلة الجمع كتل الضرب والقسمة والأسي. بوجود مثل هذه المجموعة ، يمكننا "جمع" التعبيرات الرياضية بأي تعقيد. ولكن يمكن أن يكون لدينا أيضًا "مكعبات" تنفذ وظائف أكثر تعقيدًا. الشكل 5. يظهر تنفيذ دالة تربيعية في نسختين - كتلة متعددة (انظر السهم مع تسمية - 1 ، وكذلك الشكل 6) ومتغير من كتلة واحدة (في الشكل 5 سهم مع تسمية 2).

صورة
الشكل 5. خياران لتنفيذ الدالة التربيعية

صورة
الشكل 6. نموذج هيكلي لحساب دالة تربيعية

هذا في الشكل 5. يبدو "غير واضح" (انظر السهم المميز 3) ، عندما يتم تكبيره بشكل صحيح (انظر الرسوم البيانية (الاتجاهات) ، المميزة 4) ، فإنه مقتنع بأن الأمر ليس في خصائص الرسومات. هذا هو نتيجة تأثير الوقت على حساب المتغيرات: المتغير y1 هو قيمة الإخراج لمتغير الكتلة المتعددة (اللون الأحمر للرسم البياني) والمتغير y2 هو قيمة خرج متغير الكتلة الواحدة (اللون الأسود). لكن كلا من هذه الرسومات تختلف عن "الرسومات المجردة" [y2 (t) ، x (t-1)] (أخضر). تم إنشاء هذا الأخير لقيمة المتغير y2 وقيمة متغير الإدخال المتأخر بدورة ساعة واحدة (انظر المتغير بالاسم x [t-1]).

وبالتالي ، كلما زاد معدل تغيير وظيفة الإدخال x (t) ، كلما كان "تأثير التعتيم" أقوى وكلما كانت الرسوم البيانية y1 و y2 أبعد من الرسم البياني [y2 (t) و x (t-1)]. يمكن استخدام "العيب" المكتشف لأغراضك الخاصة. على سبيل المثال ، لا شيء يمنعنا من تطبيق إشارة جيبية على المدخلات. سننظر في خيار أكثر تعقيدًا ، عندما يتغير المعامل الأول للمعادلة أيضًا بطريقة مماثلة. تظهر نتيجة التجربة شاشة لوسط VKPa ، كما هو موضح في الشكل. 7.

صورة
الشكل 7. نتائج المحاكاة بإشارة إدخال جيبية

تُظهر الشاشة الموجودة في أسفل اليسار الإشارة المُزوَّدة لمدخلات تحقيق دالة تربيعية. وفوقها توجد الرسوم البيانية لقيم الإخراج y1 و y2. الرسوم البيانية في شكل "أجنحة" هي قيم تم رسمها في إحداثيتين. لذا ، بمساعدة العديد من الإدراك للوظيفة التربيعية ، رسمنا نصف "الفراشة". إن رسم كل شيء هو مسألة تقنية ...

لكن مفارقات التوازي لا تنتهي عند هذا الحد. في التين. يوضح الشكل 8 اتجاهات التغيير "العكسي" للمتغير المستقل x. إنهم يمرون بالفعل إلى يسار الرسم البياني "المجرد" (هذا الأخير ، كما نلاحظ ، لم يغير موقفه!).

صورة
تين. 8. نوع الرسوم البيانية مع تغيير خطي مباشر وعكس لإشارة الإدخال

في هذا المثال ، يظهر الخطأ "المزدوج" لإشارة الخرج فيما يتعلق بقيمته "الآنية". وكلما كان نظام الحوسبة أبطأ أو كلما زاد تردد الإشارة ، زاد الخطأ. الموجة الجيبية هي مثال على التغيير الأمامي والعكسي لإشارة الإدخال. ونتيجة لذلك ، اتخذت "الأجنحة" في الشكل 4 هذا الشكل. بدون تأثير "الخطأ المتخلف" ، سيكونون ضعفين.

6. تحكم PID التكيفي


دعونا نفكر في مثال آخر يتم فيه عرض المشكلات التي تم النظر فيها. في التين. يوضح الشكل 9 تكوين وسط VKP (a) عند نمذجة وحدة تحكم PID تكيفية. يظهر أيضًا مخطط تخطيطي يتم فيه تمثيل وحدة تحكم PID بوحدة تسمى PID. على مستوى الصندوق الأسود ، فهو مشابه لتطبيق كتلة مفردة سبق اعتبارها لوظيفة تربيعية.

تظهر نتيجة مقارنة نتائج حساب نموذج وحدة تحكم PID ضمن حزمة رياضية معينة والبروتوكول الذي تم الحصول عليه من نتائج المحاكاة في بيئة VKP (أ) في الشكل 10 ، حيث الرسم البياني الأحمر هو القيم المحسوبة ، والرسم البياني الأزرق هو البروتوكول. سبب عدم تطابقها هو أن الحساب في إطار الحزمة الرياضية ، كما هو موضح في التحليل الإضافي ، يتوافق مع التشغيل المتسلسل للكائنات عندما تعمل لأول مرة على وحدة تحكم PID وتتوقف ، ثم نموذج الكائن ، إلخ. في الحلقة. تطبق بيئة VKPa / نماذج التشغيل الموازي للكائنات وفقًا للحالة الحقيقية ، عندما يعمل النموذج والكائن بالتوازي.

صورة
الشكل 9. تنفيذ وحدة التحكم PID

صورة
الشكل 10. مقارنة القيم المحسوبة مع نتائج المحاكاة للتحكم PID

نظرًا لأنه ، كما أعلنا بالفعل ، في VKP (أ) هناك وضع لمحاكاة التشغيل المتسلسل للكتل الهيكلية ، ليس من الصعب التحقق من فرضية وضع الحساب المتسلسل لوحدة تحكم PID. عند تغيير وضع التشغيل للوسيط إلى المسلسل ، نحصل على مصادفة الرسوم البيانية ، كما هو موضح في الشكل 11.

صورة
الشكل 11. التشغيل المتسلسل لوحدة التحكم PID وجسم التحكم

7. استنتاجات


في إطار CPSU (أ) ، يمنح النموذج الحسابي البرامج بخصائص مميزة للكائنات "الحية" الحقيقية. ومن هنا جاءت العلاقة التصويرية مع "الرياضيات الحية". كما تظهر الممارسة ، نحن في النماذج ملزمين ببساطة بمراعاة ما لا يمكن تجاهله في الحياة الحقيقية. في الحوسبة المتوازية ، هذا هو في المقام الأول وقت ونهاية الحسابات. بالطبع ، مع عدم نسيان كفاية النموذج الرياضي [التلقائي] إلى كائن "حي" أو آخر.

من المستحيل محاربة ما لا يمكن هزيمته. إنه بشأن الوقت. هذا ممكن فقط في خرافة. ولكن من المنطقي أن تأخذها بعين الاعتبار و / أو حتى استخدامها لأغراضك الخاصة. في البرمجة الموازية الحديثة ، يؤدي تجاهل الوقت إلى العديد من المشاكل التي يصعب التحكم فيها واكتشافها - سباق الإشارات ، وعمليات الجمود ، مشاكل المزامنة ، إلخ. إلخ تقنية VKP (أ) خالية إلى حد كبير من هذه المشاكل لأنها ببساطة تتضمن نموذجًا في الوقت الفعلي وتأخذ في الاعتبار دقة عمليات الحوسبة. يحتوي على ما يتم تجاهل معظم نظائرها ببساطة.

فى الختام. الفراشات هي فراشات ، ولكن يمكنك ، على سبيل المثال ، التفكير في نظام معادلات الدوال التربيعية والخطية. للقيام بذلك ، يكفي أن تضيف إلى النموذج الذي تم إنشاؤه بالفعل نموذج دالة خطية وعملية تتحكم في مصادفتهم. لذلك سيتم العثور على الحل عن طريق النمذجة. على الأرجح لن تكون دقيقة بالدقة التحليلية ، ولكن سيتم الحصول عليها بشكل أكثر بساطة وسرعة. وفي كثير من الحالات يكون هذا أكثر من كاف. وكثيرا ما يكون العثور على حل تحليلي سؤال مفتوح.
فيما يتعلق بهذا الأخير ، تم استدعاء AVMs. بالنسبة لأولئك الذين ليسوا على اطلاع أو نسيوا - أجهزة الكمبيوتر التناظرية. المبادئ الهيكلية هي في كثير من عام ، والنهج لإيجاد حل.

تطبيق


1) فيديو : youtu.be/vf9gNBAmOWQ

2) أرشيف الأمثلة : github.com/lvs628/FsaHabr/blob/master/FsaHabr.zip .

3) أرشفة إصدار مكتبات Qt dll الضرورية 5.11.2 : github.com/lvs628/FsaHabr/blob/master/QtDLLs.zip

تم تطوير الأمثلة في بيئة Windows 7. لتثبيتها ، افتح أرشيف الأمثلة وإذا لم يكن لديك Qt مثبتًا أو الإصدار الحالي من Qt يختلف عن الإصدار 5.11.2 ، ثم افتح أرشيف Qt أيضًا واكتب المسار إلى المكتبات في متغير بيئة المسار. بعد ذلك ، قم بتشغيل \ FsaHabr \ VCPaMain \ release \ FsaHabr.exe واستخدم مربع الحوار لتحديد دليل التكوين لمثال ، على سبيل المثال ، \ FsaHabr \ 9.ParallelOperators \ Heading1 \ Pict1.C2 = A + B + A1 + B1 \ (انظر أيضا فيديو).

تعليق. في البداية ، بدلاً من مربع حوار تحديد الدليل ، قد يظهر مربع حوار تحديد ملف. نختار أيضًا دليل التهيئة وبعض الملفات فيه ، على سبيل المثال ، vSetting.txt. إذا لم يظهر مربع حوار تحديد التكوين على الإطلاق ، فقم قبل حذف الملف ConfigFsaHabr.txt في الدليل حيث يوجد ملف FsaHabr.exe.

من أجل عدم تكرار تحديد التكوين في مربع حوار "kernel: automatic space" (يمكن فتحه باستخدام عنصر القائمة: FSA-tools / Space Management / Management) ، انقر فوق الزر "تذكر مسار الدليل" وقم بإلغاء تحديد "عرض مربع حوار تحديد التكوين عند بدء التشغيل ". في المستقبل ، لتحديد تكوين مختلف ، يجب تعيين هذا الاختيار مرة أخرى.

المؤلفات


1. NPS ، ناقل ، الحوسبة التلقائية ، ومرة ​​أخرى ... coroutines. [المصدر الإلكتروني] ، وضع الوصول: habr.com/en/post/488808 مجانًا. ياز. الروسية (تاريخ العلاج 02.22.2020).
2. هل الآلات الآلية شيء حدث؟ [المصدر الإلكتروني] ، وضع الوصول: habr.com/en/post/483610 مجانًا. ياز. الروسية (تاريخ العلاج 02.22.2020).
3. BUCH G. ، RAMBO J. ، JACOBSON I. UML. دليل المستخدم. الطبعة الثانية. أكاديمية تكنولوجيا المعلومات: موسكو ، 2007. - 493 ص.
4 - روجاتشيف جي. الإصدار 5 من Stateflow. دليل المستخدم. [مورد إلكتروني] ، وضع الوصول: bourabai.kz/cm/stateflow.htm مجانًا. ياز. الروسية (تاريخ التداول 10.04.2020).
5.نموذج الحوسبة المتوازية [المصدر الإلكتروني] ، وضع الوصول: habr.com/en/post/486622 مجانًا. ياز. الروسية (تاريخ التداول 04/11/2020).

All Articles