Je travaille sur une application pour pouvoir surveiller les informations de production sur un mur vidéo 3x3 (donc 9 écrans). Un des jeux d'écran sur lesquels je travaille en ce moment récupère des informations et les formats pour les afficher sur l'écran. Il faut environ 2 secondes pour récupérer et formater ces données (juste une estimation approximative, pas réellement mesurée). Parce qu'il fait 9 écran, l'un après l'autre, il y a un temps très visible pour passer à ce jeu d'écran. Le PC qui pilote ce mur vidéo a 8 cœurs de traitement, alors qu'un processeur est en train de faire tout ce travail, il y a beaucoup de puissance de traitement qui reste inactive. Ma première pensée est que j'ai besoin d'utiliser le multi-threading. Malheureusement, je suis très nouveau à ce concept. Je ne l'ai vraiment utilisé qu'une seule fois. J'ai essayé de créer un BackgroundWorker et d'avoir la routine DoWork pour générer mon interface utilisateur. Malheureusement, il se bloque la première fois que j'essaie de créer un élément d'interface utilisateur (Dim grLine as New Grid
). J'ai réussi à contourner cela en ayant une routine factice DoWork
et générant toute mon interface utilisateur dans la routine RunWorkerCompleted
. Cela permet à ma fenêtre vierge d'apparaître immédiatement, mais aucune des interfaces que je génère n'apparaît tant que tout n'a pas été rendu.vb.Net: Création d'une interface utilisateur dans un BackgroundWorker
est ici une version très nettoyé de ce que je suis en train de faire:
For i As Integer = 1 to 9
Dim win As New MyCustomWindow
win.DisplayScreen = i ' This function in MyCustomWindow sets the Bounds
win.MyShow({1, 2}) ' Sample args
Globals.VideoWall.Windows(i) = win
Next
Classe MyCustomWindow:
Class MyCustomWindow
Public Sub MyShow(a() as Integer)
Me.Show() ' Has a "Loading..." TextBlock
Dim bw as New ComponentModel.BackgroundWorker
AddHandler bw.DoWork, AddressOf Generate_UI_DoWork
AddHandler bw.RunWorkerCompleted, AddressOf Generate_UI_Complete
bw.RunWorkerAsync(a)
End Sub
Private Sub Generate_UI_DoWork((sender As Object, e As ComponentModel.DoWorkEventArgs)
' Pass our arguments to the Complete routine.
e.Result = e.Argument
End Sub
Private Sub Generate_OpsMarket_Complete(sender As Object, e As ComponentModel.RunWorkerCompletedEventArgs)
Dim IDs() as Integer
IDs = e.Result
Dim grLine As New Grid ' We crash here if this code is in DoWork instead of RunWorkerCompleted
For Each id As Integer In IDs
grLine.RowDefinitions.Add(New RowDefinition)
Dim txt as New TextBlock ' For a header
grLine.Children.Add(txt)
grLine.RowDefinitions.Add(New RowDefinition)
Dim MyCtrl as New MyCustomControl()
MyCustomControl.GetData(id)
grLine.Children.Add(MyCtrl.MyGrid)
txt.Text = MyCtrl.Header
Next
txLoading.Visibility = Visibility.Hidden
grRoot.Children.Add(grLine)
End Sub
End Class
J'ai essayé de laisser suffisamment de détails dans le code si nous espérons qu'il » Sois évident ce que j'essaie d'accomplir, mais en le gardant assez petit pour ne pas être écrasant.
Edité ajouter:
La majeure partie du travail se produit dans MyCustomControl.GetData(id)
... que sous télécharge les données à partir d'un serveur Web (au format JSON), analyse le JSON, puis génère les lignes (3) et colonnes (30 ou 31, selon le mois) pour la grille et remplit les données reçues du serveur Web.
Bienvenue dans le monde du multithreading! Un couple de choses. Vous voulez profiter pleinement de 8 cœurs logiques, et la manière de le faire est d'utiliser 8 threads ou plus pour faire un tas de travail qui peut être séparé en unités de travail discrètes. Par exemple, vous voulez calculer le sqrt de tous les entiers de 1 à 1 million. Ce sont des unités de travail distinctes qui peuvent chacune être effectuées indépendamment les unes des autres, de sorte que vous laissez le système d'exploitation décider comment diviser le travail. Un seul travailleur d'arrière-plan continuera à fonctionner dans un seul thread (single core), donc pas beaucoup d'avantages là-bas. suite ... – djv
L'avantage d'un arrière-plan dans une application de formulaires est de permettre de travailler sur un thread autre que le thread UI. Cela permettra à l'interface utilisateur de continuer à actualiser et à répondre aux entrées sans l'encombrer en traitant des éléments non liés à l'interface utilisateur. Vous voulez probablement faire vos calculs sur un thread non-UI, car c'est une partie très importante de la programmation de l'interface utilisateur dans .NET. Mais pour que ces calculs soient faits rapidement, (en utilisant 8 cœurs logiques), vous voudriez multi-thread le travail en cours dans le travailleur d'arrière-plan. Si cela est logique, je peux écrire un exemple simple pour vous aider à démarrer. – djv
Ce n'est pas tellement que j'ai besoin de garder tous les 8 cœurs occupés, c'est que la façon dont je fais les choses maintenant prend beaucoup plus de temps que nécessaire. Je génère l'interface utilisateur pour 9 écrans différents, l'un après l'autre, et chaque écran prend environ 2 secondes.Dans mon code d'origine, tout ce qui était dans 'Generate_OpsMarket_Complete' dans' Generate_OpsMarket_Complete' était dans 'MyShow' ... en déplaçant la majeure partie du code dans un BackgroundWorker, l'espoir était que l'interface utilisateur de tous les écrans 9 puisse générer en parallèle au lieu de séquentiellement . – StarDestroyer