从Socket数据处理线程想到的普通Winform数据显示的应用

简介:

在前面介绍过Socket编程的文章中,有一篇是《Socket开发探秘--基类及公共类的定义》,其中介绍了一个独立线程处理类,专门在一个独立的线程中处理Socket的数据包的。摘录前面的内容介绍一下:

5 、ThreadHandler,数据独立线程处理类

对每个不同类型的数据(不同的协议类型),可以用独立的线程进行处理,这里封装了一个基类,用于进行数据独立线程的处理 

上面的工作原理是这样的,每次收到数据后,系统把数据扔给独立线程处理类,处理类放到一个队列Queue的列表中,每次从中弹出一个来处理,根据不同的协议头,分派到不同的线程来处理,这样可以提高响应速度,防止线程之间的阻塞,能够充分利用系统的资源。

 其实我们还可以把这个思想应用到日常的Winform开发中,有时候我们可能在处理一些比较费时的操作,可能是需要做一部分显示一部分,类似日常生活中的项目周报、月周报的场景,因为不可能等一个几年的项目完成后,你才告诉老板你的工作情况吧。

 借鉴Socket的数据处理方式,我在Winform程序中运用了这种数据处理方式,如我在采集赶集网的数据的时候,可以把采集到的部分数据扔给系统中的数据独立处理线程,让他们爱怎么显示就怎么显示,程序不中断,继续乐此不彼的去采集内容去,然后继续这样做(每采集一部分仍出去一部分),直到采集完毕。

     public   class  ThreadHandler < T >
    {
        
///   <summary>
        
///  处理数据线程
        
///   </summary>
        Thread _Handlehread  =   null ;
        
private   string  _ThreadName  =   "" ;
        
private  Fifo < T >  _DataFifo  =   new  Fifo < T > ();

        
///   <summary>
        
///  线程名字
        
///   </summary>
         public   string  ThreadName
        {
            
get  {  return  _ThreadName; }
            
set  { _ThreadName  =  value; }
        }

        
///   <summary>
        
///  接收处理数据
        
///   </summary>
        
///   <param name="data"></param>
         public   virtual   void  AppendData(T data)
        {
            
if  (data  !=   null )
                _DataFifo.Append(data);
        }

        
///   <summary>
        
///  数据处理
        
///   </summary>
         protected   virtual   void  DataThreadHandle()
        {
            
try
            {
                
while  ( true )
                {
                    T data 
=  _DataFifo.Pop();
                    DataHandle(data);
                }
            }
            
catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        
///   <summary>
        
///  数据处理
        
///   </summary>
        
///   <param name="data"></param>
         public   virtual   void  DataHandle(T data)
        {
        }

        
///   <summary>
        
///  开始数据处理线程
        
///   </summary>
         public   virtual   void  StartHandleThread()
        {
            
if  (_Handlehread  ==   null )
            {
                _Handlehread 
=   new  Thread( new  ThreadStart(DataThreadHandle));
                _Handlehread.IsBackground 
=   true ;
                _Handlehread.Start();
            }
            LogHelper.Info(
string .Format( " [ThreadHandler] 线程->{0}启动。。。。。。 " , _ThreadName));
        }

上面的是独立线程处理的基类,下面我们用一个子类继承他,方便代码逻辑的剥离封装:

在下面的代码中,我根据不同的Table表内容类型,放到不同的函数中进行处理,以便实现不同的显示方式。 

     public   class  TestDataHandleThread : ThreadHandler < PreData >
    {
        
public  TestDataHandleThread()
        {
            
base .ThreadName  =   " 测试数据操作处理线程 " ;
        }

        
public   override   void  DataHandle(PreData data)
        {
            
try
            {
                
if  (data.Key  ==  KeyType.PostAticle)
                {
                    
if  ( ! string .IsNullOrEmpty(data.Content.TableName))
                    {
                        ThreadPool.QueueUserWorkItem(
new  WaitCallback(Portal.gc.MainDialog.DisplayForm), data.Content);
                    }
                }
                
else   if  (data.Key  ==  KeyType.ContactInfo)
                {
                    
if  ( ! string .IsNullOrEmpty(data.Content.TableName))
                    {
                        ThreadPool.QueueUserWorkItem(
new  WaitCallback(Portal.gc.MainDialog.DisplayContactForm), data.Content);
                    }
                }
            }
            
catch  (Exception ex)
            {
                LogHelper.Error(
" [TestDataHandleThread] 测试数据操作处理线程异常:{0} "   +  ex.ToString());
            }
        }
    }

下面代码是表的不同类型的枚举类和预处理数据格式定义。

     public   enum  KeyType{PostAticle, ContactInfo};

    
///   <summary>
    
///  预处理的数据
    
///   </summary>
     public   class  PreData
    {
        
private  KeyType key;
        
private  DataTable content;

        
public  KeyType Key
        {
            
get  {  return  key; }
            
set  { key  =  value; }
        }

        
public  DataTable Content
        {
            
get  {  return  content; }
            
set  { content  =  value; }
        }

        
public  PreData(KeyType key, DataTable data)
        {
            
this .key  =  key;
            
this .content  =  data;
        }
    }

 在实际的赶集网采集程序中,我需要每采集一个链接的内容后,就处理并显示,因此示例代码如下所示:

         ///   <summary>
        
///  获取网站发布内容,并添加到线程进行处理
        
///   </summary>
        
///   <param name="itemDict"></param>
        
///   <param name="regexDict"></param>
         private   void  GetContent(Dictionary < string string >  itemDict)
        {
            
foreach  ( string  key  in  itemDict.Keys)
            {
                DataTable dt 
=   new  DataTable(key);

                
// 标题解析,省略N行代码
                
// 内容解析,省略N+N行代码

                
// 添加到线程进行处理
                Portal.gc.MainDialog.AddData( new  PreData(KeyType.PostAticle, dt));
            }
        }
         ///   <summary>
        
///  添加消息数据,根据不同的消息类型分派到不同的线程处理
        
///   </summary>
        
///   <param name="data"> 消息数据 </param>
         public   void  AddData(PreData data)
        {
            _testDataThread.AppendData(data);
        }

        
///   <summary>
        
///  采用多线程方式显示内容数据
        
///   </summary>
        
///   <param name="data"></param>
         public   void  DisplayForm( object  table)
        {
            DataTable data 
=  table  as  DataTable;
            FrmContent content 
=  FindDocument(data.TableName)  as  FrmContent;
            
if  (content  ==   null )
            {
                content 
=   new  FrmContent();
                content.TabText 
=  data.TableName;
                content.Text 
=  data.TableName;
            }           

            
this .Invoke( new  MethodInvoker( delegate ()
            {
                content.BindData(data, data.TableName);
                content.Show(
this .dockPanel);
            }));            
        }

好了,思路是思路,程序是程序,两者结合就是实践的证明,采集大量的网站连接的时候,在也不会出现主界面停顿或者假死的情况了。下面是我闲暇时间的练笔之作, 贴图以证方案之可行。

 

在采集的时候,整个程序再也不会出现假死的情况,你还可以去处理其他工作的。另外,由于涉及了线程的处理工作,你还需要定时检测处理线程,如果线程有问题,还需要重启线程就可以了,这部分是属于线程检查优化的部分,不再介绍。

本文转自博客园伍华聪的博客,原文链接:从Socket数据处理线程想到的普通Winform数据显示的应用,如需转载请自行联系原博主。



目录
相关文章
|
26天前
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
116 62
|
21天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
75 6
|
19天前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
27 2
|
24天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
24天前
|
存储 监控 安全
深入理解ThreadLocal:线程局部变量的机制与应用
在Java的多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将深入探讨`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
48 2
|
29天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
52 6
|
28天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
2月前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
2月前
|
监控 Java
在实际应用中选择线程异常捕获方法的考量
【10月更文挑战第15天】选择最适合的线程异常捕获方法需要综合考虑多种因素。没有一种方法是绝对最优的,需要根据具体情况进行权衡和选择。在实际应用中,还需要不断地实践和总结经验,以提高异常处理的效果和程序的稳定性。
30 3
|
2月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
64 4