写点什么

Silverlight 的多线程能力(上)

  • 2011-03-08
  • 本文字数:2940 字

    阅读完需:约 10 分钟

对于多线程其实一直以来都存在很多误区:比如多任务与多线程就很容易被混为一谈,而多线程也常被理所应当的认为是并行等等。而事实却是:多任务≠多线程、单任务≠单线程、多线程不一定并行,多线程与性能不成线性关系等等,其中道理在这里不再详述。笔者认为Silverlight 多线程主要作用不是在于提高性能,而是在于用户体验,其根本目的是解决用户体验中的响应速度,减少单线程带来的阻塞问题。用一个贴切的例子来形容单线程和多线程的区别:单线程就好像只有一个服务窗口卖票的车站,人们排队买票时都是单线程处理的,而且不能抢夺位置,这样只要前方有一个人出现长时间等待,后面的人都不能被响应,这就出现了单线程阻塞;而多线程就好像有多个服务窗口去卖票,这样车票买卖和等待的情况就会好很多(当然这个例子如果换成公共厕所,对于用户体验就显得更为重要了)。

这次我们就要来看看Silverlight 的多线程能力,其实Silverlight 的多线程体现在两大方面:

第一方面是将UI 线程与后台工作线程的分离,使得UI 线程可以更好地响应用户操作,而后台线程处理完后,允许通过异步的方式将处理结果推回前台进行展示。笔者认为这是多线程在Silverlight 中最主要的作用(很多传统Web 应用开发者在刚开始接触Silverlight 时很不适应这种前后台线程的异步操作)。

第二方面是对后台作业的多线程支持,比如当需要在客户端后台并行运算时,你可以通过发起多个线程来完成这些运算。在上期《Silverlight CoreCLR 结构浅析》中,我已经给大家介绍了Silverlight 的基础类库,其中就包括多线程的相关类集。

UI 线程是 Silverlight 与用户交互的线程,在 Silverlight 中 UI 线程是单一的,其中装入的是 UI 控件类及用于数据绑定的 View Model 类(什么是 View Model?就是只为 View 层服务的实体,如果要展开说会很长,就此打住!),而在后台线程中是不能直接访问这些 UI 线程中的数据与控件对象的属性。但大家不用担心,Silverlight 和 WPF 的线程模型都使用了类似于 Java Swing 中 EDT(Event Dispatch Thread)这种安全的事件分发线程模型来解决 UI 线程与其他后台线程的数据互访问题。在 Silverlight(WPF)的控件类库 System.Windows 下所有类都继承了 DependencyObject 基类,DependencyObject 类不仅提供了 Silverlight(WPF)最基础的依赖性属性服务(什么是依赖性属性?简单的说就是对象属性值依赖于其他计算值的方式,这种方式为数据绑定、动画、重用样式都提供了可行性,这里不再展开),同时也开启了 UI 线程与后台线程的数据互访通道,在 DependencyObject 中有一个非常重要的属性——Dispatcher,后台线程可以通过调用发起者(一般都是 UI 控件)的 Dispatcher 来实现互操作,后台线程可以通过下面的方式来直接操作 UI 线程中的对象:

复制代码
_UISender.Dispatcher.BeginInvoke(() =>
{
// 这里可以访问 UI 线程中的对象,因为这个委托本身就在 UI 线程中执行
}

上面的 ()=> 是 Lamda 表达式中对于无入参的委托方法的简写形式,如果有传入参数可以在括号中列明,当然你也可以使用 Action 各种重载到其他地方实现委托过程。

如果要实现 UI 线程创建并访问后台线程就更加简单,Silverlight 提供了多种创建后台线程的方式:

  • 基于普通的 System.Threading.Thread 类创建后台线程
    Thread 类是最基础的多线程类,它可以创建一个独立运行的线程,比如:
复制代码
Threadthread = new Thread(obj.functionName);
thread.IsBackground = true;
thread.Start();

但 Thread 对于线程的监控、销毁、回调都比较复杂,因此笔者往往使用 Thread 来完成一些简单的且不需要回调的任务。

  1. 基于 System.Windows.Threading.DispatchTimer 类创建后台定时器线程
    DispatchTimer 类是 Silverlight(WPF)里才出现的后台线程定时器,相较于原有 System.Threading.Timer 差别在于 DispatchTimer 是真正的在后台线程内独立执行,而 Timer 仍然在 UI 线程中执行,只是定时获得 UI 线程控制权而已。DispatchTimer 只适合于定时执行的任务,你可以根据需要来设置等待时歇,其创建方式如下:
复制代码
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 10);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
void dt_Tick(object sender, EventArgs e)
{
// 超过等待时歇时发生
// 这里可以访问 UI 线程中的对象
// 如果要结束定时器可以调用 dt.Stop();
}

DispatcherTimer 其实也是除 StoryBoard 外可以实现动画的重要组件,当然要慎用 DispatcherTimer 来构建过多后台线程,否则会使 CPU 调度开销增加反而影响效率!(调度开销将在下部分讲解)

  1. 基于 System.ComponentModel.BackgroundWorker 类轻松创建后台线程
    微软在 WinForm 架构中就引入了 BackgroundWorker 类,这个类内建了许多线程包装方法,从而大大简化线程交互的编码过程。在 Silverlight(WPF)中也可以通过 BackgroundWorker 类来轻松创建后台线程,其创建方式如下:
复制代码
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler((object, doworkeventarg) =>obj.function());
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
if(!bw.IsBusy) bw.RunWorkerAsync();
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// 任务完成时回调事件
}

BackgroundWorker 也可以通过 ReportProgress(intpercentProgress) 方法来向其他线程报告其进度完成情况,当然这只适合于可量化进度的后台工作线程,其实现如下:

复制代码
// 后台线程 obj.function() 中
obj.ReportProgress(i);
// 在 UI 线程中定义报告时间委托
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// 显示进度的相关处理方法
}
  1. 基于 System.Threading.ThreadPool 静态类创建后台线程
    在所有多线程解决方案中,ThreadPool 线程池是笔者最常用的技术。其优点在于易于控制并且减少开销,在线程池中的线程不会由于完成一个任务就消亡,而是会继续执行其他的任务,大大减少了线程的创建与销毁开销。ThreadPool 中的 QueueUserWorkItem 方法可以将任何处理函数排入后台线程队列中执行,其创建方式也非常简单:
复制代码
obj.OnEvent += (object, eventarg) => Dispatcher.BeginInvoke(UI_OnEvent);
ThreadPool.QueueUserWorkItem(state =>obj.function(), stat);
voidUI_OnEvent()
{
// 后台线程事件发生时的回调事件
}

在后台线程对象 obj 中你可以随意定义回调事件,并通过 Dispatcher.BeginInvoke 的方法来通知 UI 线程的委托。这样的方式比较简单而且实用。当然 ThreadPool 类还提供了 RegisterWaitForSingleObject 方法来实现 Timer 定时器的功能,可以说 ThreadPool 是在企业应用中比较常用的多线程实现类。

至此,就给大家介绍了 Silverlight 常用多线程实现方式,但笔者还要强调的是:Silverlight 的多线程是为了提升用户体验。其实 Silverlight 开发围绕的关键是用户体验,用户体验在现代商业应用开发中的地位非常的重要。本主题的下半部分,笔者将通过一个实例来为大家讲述 Silverlight 的多线程性能,以及与其他 Web 开发技术的性能对比。

2011-03-08 23:123700

评论

发布
暂无评论
发现更多内容

大咖说|《商业评论》主编颜杰华:如何看待未来商业的管理趋势?

大咖说

大咖说 财经 数智化 商业评论

HTTP流量神器Goreplay核心源码详解

华为云开发者联盟

Go 流量 GOREPLAY TCP/HTTP

自我认为挺全面的【Web Service渗透测试总结】

H

网络安全 渗透测试

开源每周问答精选:PolarDB for PostgreSQL 是专门面向 OLAP 场景吗?

阿里云数据库开源

数据库 阿里云 开源 polarDB

千万级CPS的开源网络压测软件dperf

百度开发者中心

政企机构用户注意!蠕虫病毒Prometei正在针对局域网横向渗透传播

火绒安全

局域网共享 渗透 蠕虫 病毒 政企

龙蜥下游发行版 Alibaba Cloud Linux 3 安全基线正式通过 CIS 认证,云上企业安全性保障更上层楼

OpenAnolis小助手

Linux 开源 cis

学术论坛第七期:基于统计的预测算法

云智慧AIOps社区

统计学 预测模型

编译ORB-SLAM 3 出现slots_reference错误

Ayosh

slam

百年奥运的凌空之美,AI云智剪背后的新算法

阿里云视频云

刷屏的“1620”有多难?3D+AI技术带你一秒看懂

百度开发者中心

3步教你把个人应用服务部署到云服务器ECS上

阿里云弹性计算

Docker 征文投稿 玩转ECS

罗马建立在水渠上:为什么需要优先建设绿色光网?

脑极体

SQL注入如何预防?

喀拉峻

网络安全

一文带你使用 Python 实现Socket编程

宇宙之一粟

Python socket 2月月更

面试突击:说一下线程生命周期,以及转换过程?

CRMEB

35款FL插件免费下载

懒得勤快

网络安全kali渗透学习 web渗透入门 NMAP高级使用技巧和漏洞扫描

学神来啦

教你一个快速视频处理的神器:Python moviepy

华为云开发者联盟

Python 视频 音频 视频处理 Moviepy

Geospatial Data 在 Nebula Graph 中的实践

NebulaGraph

图数据库 知识图谱 分布式图数据库

图计算 on nLive:Nebula 的图计算实践

NebulaGraph

图数据库 知识图谱 图计算 分布式图数据库

腾讯音乐知识图谱搜索实践

NebulaGraph

图数据库 知识图谱 分布式图数据库

iLogtail——一款延迟仅在毫秒级的千万实例可观测采集器利器来了 | 龙蜥技术

OpenAnolis小助手

阿里云 开源 数据采集 技术分享

1分钟了解Prometheus的WAL机制

johncming

Prometheus WAL

剑指Offer——JVM 这些基础知识点你全掌握了吗

No Silver Bullet

JVM 垃圾回收 offer 2月月更

Flink on K8s 企业生产化实践|社区征文

张浩_house

flink 特征平台 新春征文

OpenHarmony移植案例与原理:startup子系统之syspara_lite系统属性部件

华为云开发者联盟

Token OpenHarmony startup子系统 syspara_lite系统

netty系列之:channelHandlerContext详解

程序那些事

Java Netty nio 程序那些事 2月月更

使用goby检测log4j漏洞

网络安全学海

黑客 网络安全 信息安全 渗透测试 WEB安全

Python代码阅读(第75篇):阶乘

Felix

Python 编程 阅读代码 Python初学者 阶乘

WeOpen Good 开源公益计划正式启动!聚开源智慧·行科技向善

腾源会

开源 公益 腾源会

Silverlight的多线程能力(上)_Java_吴磊_InfoQ精选文章