elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Introducción a Git (Primera Parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  thread multihilos
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: thread multihilos  (Leído 3,916 veces)
Juan Sanchez

Desconectado Desconectado

Mensajes: 14


Ver Perfil
thread multihilos
« en: 2 Noviembre 2017, 15:45 pm »

Que tengan un buen dia a todos los integrantes del foro.
Quiero hacerles la consulta, cuando utilizo thread dentro de otro thread se bloquea mi ventana, no se si es bueno aplicar un hilo dentro de otro hilo, si trabajo con un hilo todo bien pero agrego otro hilo dentro de la misma es ahi donde se bloque mi ventana.

Tal ves no tenga sentido pero lo que quiero hacer es cargar de un datatable a listview pero con el primer hilo tarda en cargar datos en el listview y por cada fila al agregar un item en listview se tarda pero la idea es acelerar la carga y la idea que tuve es por cada fila en datatable disparar otro hilo y es ahí donde empieza a bloquear mi ventana, pero la carga de datos a listview es rápido.

la pregunta es si es conveniente utilizar un hilo dentro de otro o hay otra forma de hacer hilos anidados si que me bloquee mi ventana.

El código es lo siguiente para que se me entienda bien...

Gracias de antemano por sus respuestas


Código
  1. Imports System.Data.SqlClient
  2. Imports System.Threading
  3. Imports System.ComponentModel
  4. <Microsoft.VisualBasic.ComClass()> <ToolboxBitmap(GetType(System.Windows.Forms.ListView))> <System.Serializable()> Public Class ListView
  5.  Inherits Windows.Forms.ListView
  6.  Dim thSQL As Thread
  7.  Dim _sq As String, _decimales As Integer, _EllipseIcon As Boolean, _bordColor As Pen
  8.  Public Sub SQLConsulta(ByVal sq As String, Optional ByVal EllipseIcon As Boolean = False, Optional ByVal borderColor As Pen = Nothing, Optional ByVal decimales As Integer = 0)
  9.    _sq = sq : _decimales = decimales : _EllipseIcon = EllipseIcon : _bordColor = borderColor
  10.    thSQL = New Thread(AddressOf SQLConsultaInterno)
  11.    thSQL.Start()
  12.  End Sub
  13.  Private Sub SQLConsultaInterno()
  14.    Try
  15.      Dim h As Thread
  16.      Dim conexion As SqlConnection = New SqlConnection()
  17.      conexion.ConnectionString = "Data Source=ip_server,1433;Failover Partner=ip_server2,1433;Network Library=DBMSSOCN;MultipleActiveResultSets=true;Initial Catalog=DB;User ID=sa;Password=contraseña;" : conexion.Open()
  18.      Dim ds As New DataSet(), da As New SqlDataAdapter(_sq, conexion) : da.Fill(ds, "tabla")
  19.      If ds.Tables("tabla").Columns.Count = 1 Then
  20.        For c As Integer = 0 To ds.Tables("tabla").Columns.Count - 1
  21.          AddColumn(ds.Tables("tabla").Columns(c).Caption)
  22.        Next
  23.      Else
  24.        For c As Integer = 1 To ds.Tables("tabla").Columns.Count - 1
  25.          AddColumn(ds.Tables("tabla").Columns(c).Caption)
  26.        Next
  27.      End If
  28.      With ds.Tables("tabla")
  29.        For filas As Integer = 0 To .Rows.Count - 1
  30.          Dim ob As New ROW
  31.          ob.fila = .Rows(filas)
  32.          ob.columnas = .Columns.Count
  33.          ob.index = filas
  34.          h = New Thread(AddressOf agregar)
  35.          h.Start(ob)
  36.        Next
  37.      End With
  38.      conexion.Close()
  39.    Catch ex As Exception
  40.  
  41.    End Try
  42.  End Sub
  43.  Private Sub agregar(obj As Object)
  44.    Dim rw As ROW = DirectCast(obj, ROW)
  45.    If rw.columnas = 1 Then
  46.      Dim Registro As New ListViewItem(rw.fila.Item(0).ToString.Trim, rw.index)
  47.      AddItem(Registro)
  48.    Else
  49.      Dim Registro As New ListViewItem(rw.fila.Item(1).ToString.Trim, rw.index)
  50.      Registro.Tag = rw.fila.Item(0).ToString.Trim
  51.      For c As Integer = 2 To rw.columnas - 1
  52.        Registro.SubItems.Add(rw.fila.Item(c).ToString().Trim)
  53.      Next
  54.      AddItem(Registro)
  55.    End If
  56.  End Sub
  57.  
  58.  Delegate Sub AddColumns(ByVal texto As String)
  59.  Private Sub AddColumn(ByVal texto As String)
  60.    If Me.InvokeRequired Then
  61.      Dim d As New AddColumns(AddressOf AddColumn)
  62.      Invoke(d, New Object() {texto})
  63.    Else
  64.      Me.Columns.Add(texto)
  65.    End If
  66.  End Sub
  67.  Delegate Sub AddItems(ByVal item As ListViewItem)
  68.  Private Sub AddItem(ByVal item As ListViewItem)
  69.    If Me.InvokeRequired Then
  70.      Dim d As New AddItems(AddressOf AddItem)
  71.      Invoke(d, New Object() {item})
  72.    Else
  73.      Me.Items.Add(item)
  74.    End If
  75.  End Sub
  76.  
  77.  Private Class ROW
  78.    Property fila As DataRow
  79.    Property columnas As Integer
  80.    Property index As Integer
  81.  End Class
  82. End Class


En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.348


Ver Perfil
Re: thread multihilos
« Respuesta #1 en: 2 Noviembre 2017, 16:36 pm »

De entrada el tema, no debiera haberse puesto aquí. este hilo es para VB6.0 y versiones previas, el adecuado es en .net: https://foro.elhacker.net/net-b62.0/

El tema d ela actualización de vistas, ya se ha tratado.
Se ralentiza cuando un control tras añadir un ítem, trata de actualizar la vsta... entonces si en vez de querer añadir 1 sólo ítem se pretende añadir cientos o miles, el control debe repintarse cientos o miles de veces, de ahí la lentitud...

La solución?, Hay varias...
1 - La más sencilla es ver si el control admite un método AddRange(items), con lo que puedes pasarle un array o colección de algún tipo... (ver sobrecargas).

2 - Otra opción en NET (cuando programas controles del propio NET) es usar los métodos:
    
Código:
objeto.BeginUpdate
    objeto.DataSource = elArray
    objeto.EndUpdate
...cuya misión es precisamente evitar el redibujado. BeginUpdate y EndUpdate marcan el inicio y fin del 'NO-redibujado'...

3 - La práctica cuando el objeto no admite ninguna opción al respecto:
  
Código:
objeto.visible =false
   bucle desde 0 hasta array.count ' o el tope del objeto que sea.
      objeto.addItem(array(k))
   fin bucle
   objeto.visible=true
De hecho este mismo código puede ser parte de una función que tú crees llamada precisamente AddRange(coleccion de algún tipo)

De este modo, fuerzas a que no se redibuje con cada añadido. El propio control (salvo que esté muy mal programado), cuando se añade un ítem no intentará redibujar si resulta que el control no está visible, en consecuencia no pierde tiempo en redibujarlo x veces, si no sólo una al final, cuando lo haces visible de nuevo.


Entonces te darás cuenta que no necesitas múltiples hilos para actualizar un control, de hecho no es aconsejable, porque se pelearán (competirán) por el acceso al control. Los hilos múltiples son adecuados para trareas asíncronas, y esta es una tarea síncrona.


P.d.:
OJO: El pseudocódigo:
 
Código:
objeto.visible =false
   bucle desde 0 hasta array.count ' o el tope del objeto que sea.
      objeto.addItem(array(k))
   fin bucle
   objeto.visible=true
No considera el caso de que el objeto esté invisible, en realidad si fue ocultado desde otro lado, aquí no debería hacerse visible.
 
Código:
   Buleano v = objeto.visible
   objeto.visible =false
   bucle desde 0 hasta array.count ' o el tope del objeto que sea.
      objeto.addItem(array(k))
   fin bucle
   objeto.visible=v ' esto es, reasignamos el mismo estado que tenía previamente


« Última modificación: 2 Noviembre 2017, 16:45 pm por NEBIRE » En línea

Eleкtro
Ex-Staff
*
Desconectado Desconectado

Mensajes: 9.788



Ver Perfil
Re: thread multihilos
« Respuesta #2 en: 4 Noviembre 2017, 02:21 am »

La solución óptima ya te la ha explicado el compañero @NEBIRE, así que me centraré en puntualizar algunas otras cosas mejorables y que son bastante importantes:

1. La próxima vez, y siempre que las circunstancias sean las correctas, en lugar de optar por el uso de la clase System.Threading.Thread deberías utilizar la clase System.ComponentModel.BackgroundWorker, ya que está especificamente diseñada para simplificar y optimizar la interacción con la UI mediante su modelo de clase orientado a eventos.

Para todo lo demás, en lugar de la clase System.Threading.Thread deberías recurrir a la clase System.Threading.Tasks.task, o hacer uso de las palabras reservadas Async y Await. En general utilizar la clase Thread es una solución poco óptima si no existe una necesidad real de crear un Thread de forma explícita, como sería por ejemplo para crear y configurar opciones por thread (sería algo similar a configurar opciones por aplicación u opciones por usuario), o para crear un Thread persistente (durante el tiempo de ejecución de la aplicación) que necesite ser identificado cada cierto tiempo por el motivo que fuese...

2. Siempre que una clase no tenga la necesidad de ser heredable, como es el caso de la clase que definiste en tu código con nombre "Row", deberías asignarle el modificador NotInheritable a la firma del miembro para obtener una micro-optimización en la instanciación del tipo y por ende una micro-optimización más notable en la carga de datos de varios elementos del mismo tipo al representarlos en un control.

3. En tu clase o control de usuario "ListView" estás utilizando tipos que implementan la interfáz IDisposable como es el caso de la clase System.Drawing.Pen, al instanciar este tipo de clases generan recursos no administrados (nativos) que deben ser liberados mediante el método IDisposable.Dispose() ( Pen.Dispose() ), así que deberías sustituir la implementación heredada de la interfáz IDisposable para completar su funcionalidad liberando esos nuevos recursos no heredados que estás utilizando en tu código...

En este caso en específico con objetos de tipo Pen y SolidBrush y etc. se debe tener en cuenta que existe un límite máximo de recursos de GDI que un proceso puede mantener abiertos (el cual está especificado en el registro de Windows, como muchas otros límites varios), aunque dicho límite es exageradamente elevado y eso lo hace casi "inalcanzable" por una aplicación de consumo general... claro está a menos que los recursos se administren mal, si generamos varias decenas de miles de recursos nativos GDI en un intervalo corto de tiempo, un intervalo más corto del que el GC puede recojer más recursos a tiempo de los que se generan, y rebasar dicho límite.

Lo que quiero decir es que... el método Dispose está para algo, existe para ser utilizado, para ayudar al GC en la liberación de dichos recursos en el intervalo más corto posible de tiempo, no para ignorarlo y dejar que el GC empiece la liberación cuando le de la gana (o que al final no lo haga), así que dale uso al método Dispose, este mensaje va dirigido a todo el mundo/programador de .NET que lo lea, que estoy bastante mosqueado de ver siempre como personas "aprenden a programar en .NET" sin aprender lo básico y fundamental para elaborar un programa estable y sin fugas, pues no liberar los recursos de un objeto cuando ya no se necesitan ser utilizados es algo que se considera una de las peores y más horribles prácticas en la programación orientada a objetos.

Ejemplo:

Código
  1. Public Class MyListView : Inherits ListView
  2.  
  3.    Private MyPen As Pen
  4.  
  5.    Public Sub New()
  6.        Me.MyPen = New Pen(Color.Empty)
  7.    End Sub
  8.  
  9.    Protected Overrides Sub Dispose(disposing As Boolean)
  10.        If (disposing) Then
  11.            ' Aquí llamas al método Pen.Dispose()
  12.            ' y adicionálmente anulas la referencia
  13.            ' para optimizar (acortar) el intervalo de tiempo
  14.            ' en el que efectuará el GarbageCollector.
  15.            Me.MyPen.Dispose()
  16.            Me.MyPen = Nothing
  17.        End If
  18.  
  19.        ' Aquí llamas al método base Dispose() de la herencia para liberar los
  20.        ' recursos por defecto utilizados por la clase ListView.
  21.        MyBase.Dispose(disposing)
  22.    End Sub
  23.  
  24. End Class

Saludos.
« Última modificación: 4 Noviembre 2017, 04:22 am por Eleкtro » En línea

Juan Sanchez

Desconectado Desconectado

Mensajes: 14


Ver Perfil
Re: thread multihilos
« Respuesta #3 en: 7 Noviembre 2017, 20:58 pm »

Bueno agradecerles a nebire y elektro por sus conceptos bien puntualizados, sobre todo en la administración de recursos de un objeto.
Les agradezco mucho por haberme despejado dudas sobre programación en net.
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Emular MultiHilos (multithread) Sin Fork (FAKE FORK) « 1 2 »
PHP
OzX 14 8,877 Último mensaje 27 Marzo 2009, 00:24 am
por OzX
#include <thread/AsyncCallback.h> #include <thread/Runnable.h>
GNU/Linux
Codename!! 1 2,848 Último mensaje 18 Agosto 2011, 07:14 am
por Foxy Rider
#include <thread/AsyncCallback.h> #include <thread/Runnable.h>
Programación C/C++
Codename!! 0 2,064 Último mensaje 15 Agosto 2011, 21:31 pm
por Codename!!
Multihilos
Java
m@o_614 1 1,885 Último mensaje 28 Septiembre 2015, 17:54 pm
por MGGM
Tutorial para multihilos en C (windows.h)
Programación C/C++
galapok11 1 2,670 Último mensaje 26 Agosto 2016, 15:53 pm
por ivancea96
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines