Map PureBasic vs Tableau associatif PHP7

Vous avez une idée pour améliorer ou modifier PureBasic ? N'hésitez pas à la proposer.
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Map PureBasic vs Tableau associatif PHP7

Message par Ollivier »

Erix14 a écrit :C'est pour cela que Fred doit allouer de la mémoire globale pour toute
création de map, au lieu de faire du cas par cas.
Si c'est la meilleure solution, je suis d'accord, cependant, il faut que ça reste une gestion contrôlable, c'est-à-dire qu'il faut pouvoir l'activer, la désactiver et la réactiver à la volée (même si PHP ne le fait pas forcément).

[Edit]Il y a aussi le type d'algo utilisé. Le choix entre, au moins 2 algos devrait être une possibilité offerte pour appuyer soit la rapidité, soit la sécurité.

[Edit2]

Bonjour PAPIPP!

Quand tu postes un code source, c'est comme appréhender une masse, il faut du temps pour la relever!

Ce n'est pas une critique. Au contraire, voir les deux codes sources (le tien, puis celui d'Erix14) révèle l'étendue des possibilités de codage possibles d'un contexte à l'autre (de la prog de bas niveau à la prog de haut niveau).

Bien que le code d'Erix14 soit souple à n'en plus finir, ton code a la particularité de définir un algo "cousin" et rappelle que cet algo fait partie d'un immense ensemble programmable.

Dans ton explication de code préalable, j'ai dû me concentrer pour obtenir les consignes. Là, c'est une critique, mais constructive! Car tu peux ajouter des guillemets ou équivalents pour les extraits de chaîne.

mer est dans mercredi est plus difficile à comprendre que
"mer est dans mercredi" qui est, lui-même, plus difficile à comprendre que
" 'mer' est dans 'mercredi' " !
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Re: Map PureBasic vs Tableau associatif PHP7

Message par erix14 »

@Ollivier, oui, un InitMap(#PB_Type_Algo, nombre_de_Mo_alloué)
J'ai amélioré mon dernier code via une Macro 'As' après les ForEach pour coller encore plus à la syntaxe de PHP.

Code : Tout sélectionner

Structure T
	Map T.T()
	ValS.s
	StructureUnion
		ValL.l
		ValF.f
	EndStructureUnion
EndStructure
Macro As(Map, Cle, Valeur)
	: Define Cle.s = MapKey(Map) : Define Valeur.T = Map
EndMacro
Global NewMap TData.T(100000)
;{
With TData("PureBasic")\T("Commercial")\T("001")
	\T("Prenom")\ValS = "Pierre"
	\T("Nom")\ValS = "Dupond"
	\T("Age")\ValL = 25
	\T("Passe-temps")\T("Lecture")
	\T("Passe-temps")\T("Randonnée")
EndWith
With TData("PureBasic")\T("Commercial")\T("002")
	\T("Prenom")\ValS = "Paul"
	\T("Nom")\ValS = "Martin"
	\T("Age")\ValL = 29
	\T("Passe-temps")\T("Voyage")
	\T("Passe-temps")\T("Jeux vidéo")
EndWith
With TData("PureBasic")\T("Administratif")\T("003")
	\T("Prenom")\ValS = "Jean"
	\T("Nom")\ValS = "Moulin"
	\T("Age")\ValL = 41
EndWith
With TData("PureBasic")\T("Technique")\T("004")
	\T("Prenom")\ValS = "Fred"
	\T("Nom")\ValS = "Leboss"
	\T("Age")\ValL = 39
	\T("Passe-temps")\T("Jeux vidéo")
EndWith
With TData("Microsoft")\T("Commercial")\T("001")
	\T("Prenom")\ValS = "Nicole"
	\T("Nom")\ValS = "Duchemin"
	\T("Age")\ValL = 33
	\T("Passe-temps")\T("Lecture")
EndWith
With TData("Microsoft")\T("Technique")\T("002")
	\T("Prenom")\ValS = "Gérald"
	\T("Nom")\ValS = "Durand"
	\T("Age")\ValL = 38
EndWith
;}
Global NewMap TSocietes.T()
Global NewMap TSocietesTotalAge.T()
Global NewMap TServices.T()
Global NewMap TServicesTotalAge.T()
Global NewMap TPasseTemps.T()
Debug "-----------------------------------"
Debug "Liste du personnel toutes sociétés confondues :"
ForEach TData() As (TData(), Societe, *Tmp1)
	ForEach *Tmp1\T() As (*Tmp1\T(), Service, *Tmp2)
		ForEach *Tmp2\T() As (*Tmp2\T(), Reference, *Personne)
			Debug Societe + " : " + *Personne\T("Prenom")\ValS + " " + *Personne\T("Nom")\ValS + " " + Str(*Personne\T("Age")\ValL) + " ans (Réf : " + Reference + ")"
			TSocietes(Societe)\ValL + 1
			TSocietesTotalAge(Societe)\ValL + *Personne\T("Age")\ValL
			TServices(Service)\ValL + 1
			TServicesTotalAge(Service)\ValL + *Personne\T("Age")\ValL
			ForEach *Personne\T("Passe-temps")\T() As (*Personne\T("Passe-temps")\T(), PasseTemps, *TmpNul)
				TPasseTemps(PasseTemps)\ValL + 1
			Next
		Next
	Next
Next
Debug "-----------------------------------"
Debug "Âge moyen par société :"
ForEach TSocietes() As (TSocietes(), Societe, *Age)
	Debug Societe + " : " + StrF( TSocietesTotalAge(Societe)\ValL / *Age\ValL ) + " ans"
Next
Debug "-----------------------------------"
Debug "Âge moyen par service :"
ForEach TServices() As (TServices(), Service, *Age)
	Debug Service + " : " + StrF( TServicesTotalAge(Service)\ValL / *Age\ValL ) + " ans"
Next
Debug "-----------------------------------"
Debug "Liste des passe-temps :"
ForEach TPasseTemps() As (TPasseTemps(), PasseTemps, *Nb)
	Debug PasseTemps + " : " + Str(*Nb\ValL) + " fois"
Next
Pour info, j'ai contrôlé si ClearMap supprimait bien les Map imbriquées, tout est bien supprimé.
Maintenant, ce qui me manque le plus c'est un SortMap.
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Map PureBasic vs Tableau associatif PHP7

Message par Ollivier »

C'est beau! Mais est-ce que cela te fait revenir à un timing "correct"?

La macro As() que tu rajoutes optimise les maps imbriquées. Moi, a priori, j'ai un retard de ForEach sans même le besoin d'être imbriqué. Ce qui me pousse à penser qu'il y a forcément un retard multiplié dans une boucle imbriquée à 2 niveaux, un retard sur-multiplié dans une boucle imbriquée à 3 niveaux, etc... Et cela indifféremment de cette macro As() pratique.

Pour ForEach:

A la base, la productivité instantanée est excellente.
C'est son rendement moyen qui est torpillé quand les maps prêtes à accueillir leur million d'unités sont vides ou "quasiment". Et cela, dans une boucle vide:

Code : Tout sélectionner

Foreach I():Next
C'est la banane que j'ai trouvée en voulant tester celle que tu as trouvée.

Mais, un peu comme toi tu compares PureBasic 32bits avec PHP 64bits (quel malotru!), honte à moi qui teste en 522 LTS 32bits. Je vais vérifier si je n'ai pas détecté un bug déjà appréhendé.
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Re: Map PureBasic vs Tableau associatif PHP7

Message par erix14 »

La Macro ne fait que réduire le nombre d'accès aux Map, mais comme ils sont très rapides, la différence n'est pas flagrante. Pour info, en accès pur, une fois que les Map (3 niveaux) sont créées, PureBasic n'est que 2 fois plus lent que PHP. Mais ce n’est pas grave, car comme c'est des temps très rapides, il nous faudrait des millions d'accès pour sentir la différence.

Je ne sais pas si on peut dire que c'est un bug, mais en tout cas si on ne le sait pas c'est très gênant. Quand on alloue de la mémoire pour une structure qui contient une Map, celle-ci ne fonctionne pas. Il faut l'initialiser via un gabarit. Pour vous en rendre compte, commenter/décommenter la ligne 92.

Édit : code modifié en utilisant AllocateStructure / FreeStructure

Code : Tout sélectionner

EnableExplicit
UseSQLiteDatabase()
Interface ISQLite
	Query.L(Requete.S)
	GetArray.L()
	ArrayL.L(Field.S)
	ArrayQ.q(Field.S)
	ArrayF.f(Field.S)
	ArrayS.S(Field.S)
	FreeResult.L()
	Free.L()
EndInterface
Declare New_SQLite(NomBD.S)
;- Exemple
Global SQLite.ISQLite = New_SQLite(":memory:")
If SQLite\Query("CREATE TABLE IF NOT EXISTS personnes (IDPersonne INTEGER, Nom CHAR(50), Prenom CHAR(50), Age INT, PRIMARY KEY (IDPersonne))")
	SQLite\Query("INSERT INTO personnes ('Nom','Prenom','Age') VALUES ('Dupond','Pierre','25'), ('Martin','Paul','29'), ('Moulin','Jean','41'), ('Leboss','Fred','39'), ('Duchemin','Nicole','33'), ('Durand','Gérald','38')")
	If SQLite\Query("SELECT * FROM personnes ORDER BY Age ASC")
		While SQLite\GetArray()
			Debug "Identifiant : " + Str(SQLite\ArrayL("IDPersonne"))
			Debug "Prénom : " + SQLite\ArrayS("Prenom")
			Debug "Nom : " + SQLite\ArrayS("Nom")
			Debug "Âge : " + Str(SQLite\ArrayL("Age"))
			Debug "-------------------------------"
		Wend
		SQLite\FreeResult()
	EndIf
EndIf
SQLite\Free()
End
;- Class SQLite
Structure SQLite
	*VirtualTable.ISQLite
	SQLite.L
	NomBD.S
	Requete.S
	Map Fields.L()
	NumFields.L
EndStructure
Procedure.L SQLite_Free(*This.SQLite)
	CloseDatabase(*This\SQLite)
	FreeStructure(*This)
EndProcedure
Procedure.L SQLite_Query(*This.SQLite, Requete.S)
	Protected t.L, Tmp.S, Result.L = #False
	If Requete
		*This\Requete = Requete
		Tmp = UCase(Trim(Requete))
		If FindString(Tmp, "SELECT", 1, #PB_String_NoCase) = 1
			If Not DatabaseQuery(*This\SQLite, Requete)
				MessageRequester("Erreur requête SQLite", DatabaseError()+Chr(10)+Chr(10)+Requete)
			Else
				ClearMap(*This\Fields())
				*This\NumFields = DatabaseColumns(*This\SQLite) - 1
				For t=0 To *This\NumFields
					*This\Fields(DatabaseColumnName(*This\SQLite, t)) = t
				Next
				Result = #True
			EndIf
		Else
			If Not DatabaseUpdate(*This\SQLite, Requete)
				MessageRequester("Erreur requête SQLite", DatabaseError()+Chr(10)+Chr(10)+Requete)
			Else
				Result = #True
			EndIf
		EndIf
		ProcedureReturn Result
	EndIf
EndProcedure
Procedure.L SQLite_GetArray(*This.SQLite)
	ProcedureReturn NextDatabaseRow(*This\SQLite)
EndProcedure
Procedure.L SQLite_ArrayL(*This.SQLite, Field.S)
	ProcedureReturn GetDatabaseLong(*This\SQLite, *This\Fields(Field))
EndProcedure
Procedure.q SQLite_ArrayQ(*This.SQLite, Field.S)
	ProcedureReturn GetDatabaseQuad(*This\SQLite, *This\Fields(Field))
EndProcedure
Procedure.f SQLite_ArrayF(*This.SQLite, Field.S)
	ProcedureReturn GetDatabaseFloat(*This\SQLite, *This\Fields(Field))
EndProcedure
Procedure.S SQLite_ArrayS(*This.SQLite, Field.S)
	ProcedureReturn GetDatabaseString(*This\SQLite, *This\Fields(Field))
EndProcedure
Procedure.L SQLite_FreeResult(*This.SQLite)
	ProcedureReturn FinishDatabaseQuery(*This\SQLite)
EndProcedure
ProcedureDLL New_SQLite(NomBD.S)
	Protected *Occurence.SQLite = AllocateStructure(SQLite)
	*Occurence\VirtualTable = ?VirtualTable_SQLite
	*Occurence\SQLite = OpenDatabase(#PB_Any, NomBD, "", "")
	*Occurence\NomBD = NomBD
	If *Occurence\SQLite
		ProcedureReturn *Occurence
	Else
		FreeStructure(*Occurence)
		ProcedureReturn #Null
	EndIf
	DataSection 
		VirtualTable_SQLite: 
		Data.L @SQLite_Query()
		Data.L @SQLite_GetArray()
		Data.L @SQLite_ArrayL()
		Data.L @SQLite_ArrayQ()
		Data.L @SQLite_ArrayF()
		Data.L @SQLite_ArrayS()
		Data.L @SQLite_FreeResult()
		Data.L @SQLite_Free()
	EndDataSection
EndProcedure
Dernière modification par erix14 le lun. 10/août/2015 17:29, modifié 1 fois.
Fred
Site Admin
Messages : 2648
Inscription : mer. 21/janv./2004 11:03

Re: Map PureBasic vs Tableau associatif PHP7

Message par Fred »

Pour AllocateMemory(), c'est voulu. Cette commande ne fait que allouer de la memoire, rien d'autre. Si tu veux que ta structure qui contient des types complexes soit operationnelle, tu dois utiliser 'InitializeStructure' (et ClearStructure() avant le FreeMemory()), ou plus simple, 'AllocateStructure()' (et FreeStructure())

http://www.purebasic.com/documentation/ ... cture.html

http://www.purebasic.com/documentation/ ... tions.html
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Re: Map PureBasic vs Tableau associatif PHP7

Message par erix14 »

Merci Fred pour ces fonctions. En cherchant dans la doc française, je ne les retrouve que dans l'historique de version : 23 Juillet 2014 : Version 5.30 => - Ajouté: AllocateStructure(), FreeStructure()
Il semblerait qu'elles n'aient pas été ajoutées dans la doc.
Répondre