Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Avocatul Poporului vs European Om...

Recomandari firme pentru draperii...

Receptie Eutelsat 5 West. Este po...

Poti receptiona semnal de la mai ...
 Cabluri HDMI 2.1 de 4m-5m care sa...

Zoom comparat cu Google Meet

Monitor/Display wireless?

Pornire greoaie dupa cateva zile ...
 De la un proiect scris in python ...

Audi A4 B9 quattro 190 CP!

Tepari la pariuri pe TikTok

Banca imi cere justificativ fondu...
 schema pcb ELECTRA CIM150 PAS

Probleme stomac

Sfat achizitie bicicleta oras

Canalele Sky Showtime 1 și S...
 

"Ascultarea" continua pe un stream de intrare

* * * * * 1 votes
  • Please log in to reply
11 replies to this topic

#1
Rhesus

Rhesus

    Senior Member

  • Grup: Senior Members
  • Posts: 2,882
  • Înscris: 22.04.2014
Va salut.

Va cer o parere in legatura cu un subiect destul de interesant as putea spune.

Introducere scurta:
Se da un dispozitiv, si o aplicatie care comunica cu acesta. Aparatul trimite in mod constant pachete prin intermediul unei interfete seriale (asemanator Arduino, dar vorbim de ceva mai complex).
Doresc ca aplicatia sa "asculte" in mod continuu (sa primeasca pachetele, sa parseze, si sa modifice corespunzator business logic-ul). Doresc ca aceasta abordare sa fie real-time - cerinta obligatorie (mai corect spus, cu latenta minima...), vorbind de un domeniu critic.
Ce stim despre pachete:
Pachetele vin intr-un format de tipul:
byte1 byte2 - intotdeauna aceelasi (0x55 respectiv 0xAA)
byte3 - contine nr. de bytes efectivi de date ai pachetului (body-ul) + 1 (el insusi)
si apoi nr = (byte3 - 1) bytes cu continutul instructiunii.
Exemplu:
0x55 0xAA 0x04 0x01 0x02 0x03
Continutul instructiunii fiind 0x01 0x02 0x03 (unde, nu are relevanta, ultimul byte este un checkSum, pentru a verifica integritatea pachetului).

DataReader dr = new DataReader(device.InputStream);
			 while (true)
			 {
				 var bytesReceived = await dr.LoadAsync(3);
				 if (bytesReceived > 0)
				 {
					 byte[] myArray = new byte[bytesReceived];
					 dr.ReadBytes(myArray); // 0X55 0XAA 0x<cati mai urmeaza - 1>
					 if (myArray[0] == 0X55 && myArray[1] == 0xAA)
					 {
						 // citim restul pachetului
						 var nextBytesReceived = await dr.LoadAsync((uint)myArray[2] - 1);
						 if (nextBytesReceived > 0)
						 {
							 byte[] restul = new byte[nextBytesReceived];
							 dr.ReadBytes(restul);
							 // reconstruirea intregului pachet
							 // parsare, etc. etc.
						 }
					 }			 				
				 }
			 }

  

Mentionez faptul ca metoda (in care este bucata de cod de mai sus) este asincrona, deci nu blocheaza thread-ul curent pentru eventuale alte comenzi (de trimitere de pachete spre dispozitiv, de ex.)

Totusi, nu stiu cat de eficienta este varianta aceasta din perspectiva in real-time.
Majoritatea sample-urilor (din alte proiecte asemanatoare care fac listen() continuu la Input), folosesc un buffer initial (de 1024 de bytes de ex.), iar de aici "sparg" pachetele ("cate intra"):  cum s-a reconstruit un pachet, il parseaza, etc. , daca s-a ajuns la 1024, apoi citim alt bloc de 1kb, etc.

Ideea este ca neputand sa primim 2 pachete simultan, mi se pare mai sugestiv sa citim 3 bytes, si apoi <last_byte - 1> bytes. Daca avem 10 bytes, oricum nu avem ce face cu cei 1014 bytes ramasi (in cazul abordarii din sample-uri).

Nu am un delimitator intre pachete (un token). Deci primesc un flux continuu de bytes. Ar mai fi alte variante de luat in considerare in afara de acestea?

Edited by Rhesus, 18 April 2019 - 17:23.


#2
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006
epoll?

View PostRhesus, on 18 aprilie 2019 - 17:21, said:

Nu am un delimitator intre pachete (un token).
Un token ar fi fost o solutie suboptima. Ce ai acum, ceva de genul netstring, e codarea optima, pentru ca stii la cate date sa te astepti, nu trebuie sa scanezi ca sa afli unde se termina.

Iar checksum la sfarsit bate totul in cuie.

#3
Rhesus

Rhesus

    Senior Member

  • Grup: Senior Members
  • Posts: 2,882
  • Înscris: 22.04.2014
Chiar daca monitorizez mai multe fluxuri, nestiind unde este "delimiterea" intre pachete, tot pe acolo suntem.

Ma gandeam (dar nu stiu daca aduce imbunatatiri semnificative):

- atunci cand am citit primul byte2 (adica lungimea body-ului curent), sa creez deja un Task care porneste de la byte[2 + byte2]   avand dimensiunea byte[byte2 + 4] .. si tot asa.

Dar iarasi cred ca ma invart in jurul cozii: Chiar daca stiu deja din prima faza chiar si Task-ul 5 sa zicem, conteaza ordinea (fiind sistem real-time). Nu ma ajuta sa stiu ca Task-ul 100 e terminat mai repede... cat timp nu-l pot implementa in business-logic. Tot la ceva secvential se ajunge, oricat m-as gandi, si mi-as dori sa imbunatatesc performanta...

View PostOriginalCopy, on 18 aprilie 2019 - 17:37, said:

Un token ar fi fost o solutie suboptima. Ce ai acum, ceva de genul netstring, e codarea optima, pentru ca stii la cate date sa te astepti, nu trebuie sa scanezi ca sa afli unde se termina.

Iar checksum la sfarsit bate totul in cuie.
Se multumeste frumos Posted Image Posted Image

Edited by Rhesus, 18 April 2019 - 17:52.


#4
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006
Nu vad sensul. Daca vorbim aceeasi limba, acea interfata seriala iti da date in mod serial, nu are multiplexing. Presupunand ca trebuie sa ai intregul pachet pentru a putea decide ce vrei sa faci cu el, aici:

// reconstruirea intregului pachet
// parsare, etc. etc.

poti trimite pachetul validat la checksum si fara acel header de 2 bytes magic catre un "task" - habar n-am ce e, probabil o "goroutine", "greenlet" sau o astfel de forma de "lightweight thread".

In microsoft parca aveau un nume...

A, da, fiber!

Cat despre "real-time": nu exista asa ceva, e o iluzie. Pana si lumina are o limita in vid. Exista doar latente, si iti faci grija de ele abia cand clientul se plange ca e prea lent.

Edited by OriginalCopy, 18 April 2019 - 17:56.


#5
Rhesus

Rhesus

    Senior Member

  • Grup: Senior Members
  • Posts: 2,882
  • Înscris: 22.04.2014

View PostOriginalCopy, on 18 aprilie 2019 - 17:53, said:

Nu vad sensul. Daca vorbim aceeasi limba, acea interfata seriala iti da date in mod serial, nu are multiplexing. ...
Era ideal....

#6
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006

View PostRhesus, on 18 aprilie 2019 - 17:54, said:

Era ideal....
Crezi? Eu zic sa fii fericit ca nu trebuie sa iti faci griji de pachete "out of order". Apropo, adauga la fiecare pachet cate un id unic care creste monoton, inainte de a trimite pachetul la "task". Iar id-ul acela sa fie persistent pe disk in caz de crash.

Nu stii cand o sa iti ceara cineva acel "raport de date agregate".

Edited by OriginalCopy, 18 April 2019 - 18:02.


#7
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,228
  • Înscris: 24.02.2007
Sa apelez o metoda async sa cer doar 3 bytes nu e chiar eficient. Prefer sa adun in buffere mai mari si sa procesez ulterior.

#8
Rhesus

Rhesus

    Senior Member

  • Grup: Senior Members
  • Posts: 2,882
  • Înscris: 22.04.2014
In final, am ales un buffer de 1kb pe care il interpretez, respectiv parsez pachete (o data ce am gasit unul valid). Iar latenta este foarte buna (din punctul meu de vedere) - oricum voi face si partea de testare/performanta, dar la final.

In schimb intampin un hop arhitectural.

Am ales sa fac MVVM (dat fiind ca aplicatia(ile) vor fi in Android respectiv UWP). Data binding & stuff.
Problema mea este ca aparatul meu, dupa cum am spus, trimite pachete "continuu" (pe care le parsez, modificand in consecinta business-logic-ul) - bineinteles, in model.

Ideea e ca, in maniera clasica MVVM, VM-ul implementeaza o interfata (de tipul INotifyPropertyChanged) sau mosteneste o clasa (BindableBase) (care, la baza, tot INotifyPropertyChange este Posted Image ) pentru a usura munca programatorului atunci cand vine vorba de Data Binding.

In cazul meu, modelul in sine isi modifica "starea" - asa fiind natura dispozitivului. Ii dai
Model m
[...]
m.listen();

Si el isi modifica proprietatile in functie de pachetele venite:
[...]
this.<atribut> = <valoarea data de parser>
[...]


Astfel, orice abordare clasica de tipul
ModelViewModel : BindableBase (sau INotifyPropertyChanged) {
Model m;
...
}
[...]

E non-sens. (din perspectiva MV-View)

Ce variante "frumoase" as avea, pentru a evita alterarea modelului? Respectiv, sa nu fac ceva ce "nu se face"
Model : BindableBase

(sau orice alta alterare a modelului cu event-uri, delegate-uri, etc.). De asemenea, nu e o varianta nici mostenirea modelului, si dezvoltarea unui model "custom" cu partea de event-uri implementata.

Ma gandeam la implementarea Aspect Oriented-Programming prin adaugarea de advice-uri la nivelul modelului existent. Un fel de notify aspect.
Ce parere aveti?

Edited by Rhesus, 03 May 2019 - 23:40.


#9
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,228
  • Înscris: 24.02.2007
Sa luam un exemplu simplu unde ceva se actualizeaza mereu: temperatura (sa zicem la o secunda).

In UI am un binding simplu spre o proprietate a ViewModel:
<StackPanel Orientation="Horizontal">
	<Label Content="{Binding Path=Temperature}"></Label>
	<Label Content="°C"></Label>
</StackPanel>


In ViewModel am o proprietate si am o instanta a unei clase ce citeste temperatura. Ma abonez la evenimentul de update al acestei clase si cand aflu ca s-a schimbat temperatura, schimb proprietatea ceea ce notifica UI-ul sa se schimbe
class TemperatureViewModel : INotifyPropertyChanged
{
	public event PropertyChangedEventHandler PropertyChanged;

	protected virtual void onpropertychanged(string propertyName)
	{
		PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}

	private decimal _temperature;

	public decimal Temperature
	{
		get => _temperature;
		set
		{
			_temperature = value;
			onpropertychanged(nameof(Temperature));
		}
	}

	public TemperatureViewModel()
	{
		var sensorReader = new TemperatureSensorReader();
		sensorReader.TemperatureUpdate += (sender, args) => { Temperature = args.NewTemperature; };
	}
}


Cum arata clasa ce ofera schimbarile de temperatura? Are un eveniment si putina logica de sincronizare intre threaduri
class TemperatureSensorReader
{
	public class TemperatureUpdateEventArgs : EventArgs
	{
		public decimal NewTemperature { get; set; }
	}

	public event EventHandler<TemperatureUpdateEventArgs> TemperatureUpdate;

	public TemperatureSensorReader()
	{
		var synchronizationContext = SynchronizationContext.Current;

		new Thread(() =>
		{
			var random = new Random();
			while (true)
			{
				var temperature = (decimal)Math.Round(random.NextDouble() * 40 - 10, 2);

				synchronizationContext.Post(
					_ =>
					{
						TemperatureUpdate?.Invoke(this,
							new TemperatureUpdateEventArgs {NewTemperature = temperature});
					}, null);
				Thread.Sleep(TimeSpan.FromSeconds(1));
			}
		}).Start(); //trebuie si oprit candva
	}
}


Rezultatul?
Attached File  a.gif   5.25K   17 downloads

#10
Rhesus

Rhesus

    Senior Member

  • Grup: Senior Members
  • Posts: 2,882
  • Înscris: 22.04.2014
Mersi @dani_user.

Ideea e ca tocmai asta intrebam: Este "corect" sa introduc event-uri in modelul meu? (exact ca ai facut tu, si care e varianta clasica de lucru).
Intreb asta deoarece am creat o biblioteca pentru aparatul meu - care poate fi consumata in C# de catre orice "client": UWP app, Win Forms, etc.

Bineinteles, strict pentru un proiect, este foarte ok varianta propusa de tine. Doar ca ma gandesc din perspectiva unui posibil client (persoana) care poate nu vrea sa foloseasca Event-Oriented Programming. El vrea modelul "crud", doar cu logica din spate.
public class Device
{
private decimal _temp;
public decimal Temperature
{
get;
private set;
}
}

De aici, "clientul" se descurca. Importa modelul, si apoi vede el cum primeste notificari la modificari din cadrul modelului. Si de aici, AOP....

Edited by Rhesus, 04 May 2019 - 17:31.


#11
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,228
  • Înscris: 24.02.2007
event e chiar keyword in limbaj. De ce sa ezit sa-l folosesc daca ma ajuta?

Nu-mi dau seama cum te-ar ajuta AOP aici daca expui o simpla proprietate...

#12
Rhesus

Rhesus

    Senior Member

  • Grup: Senior Members
  • Posts: 2,882
  • Înscris: 22.04.2014
Ezitarea mea era din perspectiva portabilitatii codului.

Anunturi

Second Opinion Second Opinion

Folosind serviciul second opinion ne puteți trimite RMN-uri, CT -uri, angiografii, fișiere .pdf, documente medicale.

Astfel vă vom putea da o opinie neurochirurgicală, fără ca aceasta să poată înlocui un consult de specialitate. Răspunsurile vor fi date prin e-mail în cel mai scurt timp posibil (de obicei în mai putin de 24 de ore, dar nu mai mult de 48 de ore). Second opinion – Neurohope este un serviciu gratuit.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate