【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

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:123606

评论

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

爱奇艺自研QAV1编码器,将在4K高清画质为用户节省36.6%的流量

爱奇艺技术产品团队

10倍加速!爱奇艺超分辨模型加速实践

爱奇艺技术产品团队

“你们程序员不就是修电脑的吗,你牛什么牛,成功跳槽百度工资从15K涨到28K

android 程序员 移动开发

“主动离职公司还给n+1,android学生管理系统项目视频

android 程序员 移动开发

架构实战营 - 毕业总结

Julian Chu

薪水被应届生倒挂,四年Java老鸟,28岁的我裸辞了,在闭关三个后拿到阿里Offer

收到请回复

程序员 java面试 Java后端

【Android】金三银四面试集合,android面试题大全

android 程序员 移动开发

顺丰科技 Hudi on Flink 实时数仓实践

Apache Flink

大数据 flink

“终于懂了“系列,android直播面试题

android 程序员 移动开发

【Android Jetpack高手日志】ViewModel 从入门到精通,kotlin中文文档

android 程序员 移动开发

Apache Flink 在汽车之家的应用与实践

Apache Flink

大数据 flink

代码覆盖率在敏捷式软件开发过程中的实践

爱奇艺技术产品团队

英国顶级电影调色公司FilmLight发布爱奇艺定制母版渲染标准模版

爱奇艺技术产品团队

“我985毕业生,凭什么和你专科生在一起,android工程师面试题目和答案

android 程序员 移动开发

【Android 功能库】1,醍醐灌顶

android 程序员 移动开发

Vue3.x 关于组件的那些变化(新手必看篇)

码仔

vue.js 大前端 组件化 组件

鸿蒙应用开发:如何与组件库(Glide)衔接?

ZEGO即构

鸿蒙 组件库

「正确」的使用Kotlin Flow进行搜索优化,安卓软件开发

android 程序员 移动开发

『Android 技能篇』优雅的转场动画之 Transition,kotlin安卓开发教程视频

android 程序员 移动开发

【 Flutter 手势探索】我的第二本小册来了,看完我工资从12K变成了20K

android 程序员 移动开发

“你们Android的程序员不就是敲点代码吗,凭啥工资这么高

android 程序员 移动开发

腾讯看点基于 Flink 构建万亿数据量下的实时数仓及实时查询系统

Apache Flink

大数据 flink

“新常态”下的Android程序员要面对哪些压力,app架构图怎么做

android 程序员 移动开发

2021 年网易云音乐实时计算平台发展和挑战

Apache Flink

大数据 flink

【Android面试】热修复,赶紧收藏备战金三银四

android 程序员 移动开发

_带你了解腾讯开源的多渠道打包技术 VasDolly源码解析,2021移动开发者未来的出路在哪里

android 程序员 移动开发

官宣|Apache Flink 1.14.0 发布公告

Apache Flink

大数据 flink

“离开公司,你什么都不是,2021Android目前最稳定和高效的UI适配方案

android 程序员 移动开发

借助 Flink 与 Pulsar,BIGO 打造实时消息处理系统

Apache Flink

大数据 flink

GaussDB的技术发展以及在金融核心数据库国产化的最佳实践丨DAMS峰会

华为云数据库小助手

GaussDB 大会 华为云数据库

【9月Android面经分享】惜挂阿里三面,Android最新实习面试经验总结

android 程序员 移动开发

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