从异步更新进度想起的事儿——IProgress
今天,在群里向大家请教了这样一个问题:“两个对象(类、窗体或什么)之间,要完成比较频繁的报告进度更新都有哪些好的方式”,Somebody 跳出来给出了个“IProgress”,没了解过,后面围绕着它讨论学习了下。
简单来说,IProgress 是类库给出的一种解决问题的方式而非具体实现,IProgress 包括一个需要实现的 Report 方法。使用时由调用“任务”的“创建者”创建对接口的实现,也就是具体实现 Report 的方法,此时创建者便可以具体控制要如何报告、报告什么,例如在 Report 中写上这么一句简单粗暴欠揍的“ textBox1.Text = currentProgress.ToString()”,但创建者控制不了的是“什么时间报告”,因为这是由“任务”本身设定的。创建者将这个具体实现传递给“任务”,任务在其逻辑内(某个属性内或某个方法内)加上一句 IProgress.Report(xxx),实现了“什么时间报告”。
在这个逻辑中,创建者可以自由控制并专注实现如何报告,而不用关心何时接到报告(事实上,创建者也没法关心,因为何时调用 Report 方法是任务决定的,并且创建者也不必亲自“接收”报告,因为报告的方式创建者已经实现了:textBox1...);而任务专注于何时报告进度更为合理,而不用关心怎么样报告,只要在需要报告的时候调用 Report 方法就好。好处就是各管各的,看似比较合理。
Somebody Ivony 还是提醒了这种方式类似于事件的隐患,即“调用了IProgress接口后,任务抓住了IProgress对象的引用,这一点和事件是一样的,所以应当设计轻量级的IProgress对象,并且与Worker的调用方解耦”。
感谢大家和 Ivony 的解答!
试试手气 9:45:05
请教大家个事儿,如果有个类暂且叫做 worker,这个 worker 要完成一些工作(不用管具体干什么),重要的是他要对工作的进度做频繁的更新和报告(没有频繁到高大上的地步),要使其它类或对象了解 worker 的进度都有哪些比较好的机制,worker自身事件?让其它类访问 worker 的公开只读属性? 上次Ivony说到事件的坑,就想到了这个事儿 ♪慕斯⌒。²º¹⁴ 9:48:45 Ivony 说的是.NET内部控件的事件是个坑吧。 试试手气 9:50:07
控件的事件和自定义事件有区别吗? X 9:52:32
有些细节别太在意 试试手气 9:53:35
那好,那我就向大家请教一下都有哪些机制可以完成任务吧 ^^ Ivony... 9:54:24
IProgress 试试手气 9:58:25
让 worker继承 IProgress 吗? Ivony... 10:01:49
不是,你可以在MSDN上搜索相关示例。。。。 试试手气 10:01:59
我正在查看 IProgress,Ivony Ivony... 10:02:39
IProgress接口的用法是由调用任务的程序创建,任务会调用这个接口的方法来反向通知进度。 试试手气 10:38:36
void Factory()
{
var mem = new Worker();
mem.Work(new IProgress<int>());
} pubulic class Worker{
void Work(IProgress<int> progress)
{
工作逻辑();
progress.Report(i++); // 报告工作
}
} 试试手气 10:45:51
我刚才写的那个伪代码的逻辑对么,是你说的意思吗? Ivony... 10:46:09
是的,微软推荐的方案就是这样。。。。
不过这个你也可以仅做参考,这样反转通知是避免事件陷阱的一种方式。 Ivony... 10:47:20
因为反转之后,变成了Worker依赖于调用方,而调用方肯定比Worker活得久,所以自然没有属性的问题。
因为反转之后,变成了Worker依赖于调用方,而调用方肯定比Worker活得久,所以自然没有事件的问题。
而且IProgress<T>是可以与调用方解耦的,互相没有牵连。 倉ル 10:48:41 Ivony... 10:49:49
我好像想错了,刚才的请忽略,我要开会去了。。。。 试试手气 10:50:26
但我感觉里边好像缺少了一个我还没理解的,非常关键的 key 的东西,就是
怎么就“报告进度”了。请忙 倉ル 10:51:30
好像是在你 work 里工作的每个阶段 调用report 吧 试试手气 11:01:38
Report 是 IProgress 接口的唯一一个方法,就是用来报告进度的。什么时候调用 Report 不是问题,我还没理解 Report 方法怎么就向其父级 Factory 报告进度了?还是……难道……莫非……Report 并不是向 Factory 作报告的 倉ル 11:03:49
像谁报告 你是说的算的吧
你在调用work 的时候指定 报告接收者的吧 X 11:04:16
应该是取决于你怎样实现IProgress这个接口的 Ivony... 11:09:25
是的,,,,,
譬如说你可以把IProgress绑定到一个进度条上。 试试手气 11:17:57
恩,X 说的是我还没融会贯通的节点……let me see see
1 -> IProgress 既然是个接口,那使用之前应该先去实现它
2 -> 实现IProgress的对象,里边需要实现 Report 方法,所以,方法里边会明确写明“如何更新”,比如Report{ textBox1.Text = i.ToString();}
3 -> Factory 把自己创建的实现接口的这个对象给到 Worker,让 Worker 来报告进度 所以,Factory 不用管什么时候报告,是由 Worker 决定的;而 Worker 不用管具体 Factory 需要如何报告,只知道自己调用 Report 方法,Factory就能收到了 Right? Ivony... 11:19:02
Right。 你想一下,其实这个和事件是一样的。 试试手气 11:19:16
对,很类似 Ivony... 11:19:21
也就是说事件和这种类型的接口是等价的。
我之前说错了是这种结构其实没有从根本上解决事件的内存泄露问题。 Ivony... 11:21:03
回想一下事件的内存泄露怎么造成的,事件宿主会抓住所有挂接的委托的引用,委托抓住方法所属实例的引用。而事件宿主不能尽快释放就会挂掉。
用IProgress接口后,Worker抓住了IProgress对象的引用,这一点和事件是一样的,所以应当设计轻量级的IProgress对象,并且与Worker的调用方解耦。 试试手气 11:22:55
但有个问题,假如 Factory 是个窗体,需要更新进度显示在 textBox1 就像我刚才举的例子。而 Worker 是个类,假设 Factory 定义的 Report 方法里写上 textBox1.Text = xxx ,这不就是个很大的问题吗? 你的意思是,关键在于如何实现一个轻量级、解耦的 IProgress 实现。 Ivony... 11:25:17
Report方法里面写什么无关紧要,关键是你的IProgress实现类的字段。
这个类型的实例会被Worker抓住,所以其字段在Worker被释放前都不能释放。
其实呢你的Worker如果生命周期很短的话是不用考虑这个问题的。 Ivony... 11:26:20
事件的陷阱主要出现在那个Timer上,这货是个无限生命周期的东西。
属于设计失误。 试试手气 11:28:10
但假如 worker 是个周期长,长时间后台运行的东东就会增加风险 Ivony... 11:28:37
是的,,,, 试试手气 11:30:16
但很多情形,worker 都很可能是个周期长、长时间后台运行的东东。比如后台持续下载队列中的文件、持续读取或写入磁盘等 这时候,是不是就需要对 worker 自身重新审视和设计了 Ivony... 11:30:55
嗯,,,,其实有这个意识就好了,过分的纠结于这一点反倒无益。
长和短都是相对而言的。
即使生命周期很长,如果只挂一个Progress上去也没事,你不停的挂才会有事。 试试手气 11:31:51
嗯 Ivony... 11:31:57
事件的问题就在于大家经常无止尽的挂事件上去,从来不解挂,,,,
举另一个例子吧,,,,
创建一个WebClient,使用基于事件的异步。。。。 Ivony... 11:33:04
你先挂一个方法在Completed,然后导航到某个地址,加载完后会引发Completed事件。
然后你又挂一个方法到Completed,再导航,,,,
如此反复,挂了,,,,, X 11:35:37
事实上应该很少有人会对同一个对象重复注册多个相同的事件吧 Ivony... 11:36:52
Timer就会啊,,,, X 11:37:50
Timer也是只注册了一次吧 试试手气 11:45:18
去记录下这次的对话
View Dialog
哦对了,在博客园找到一篇比较直观的帖子作为推荐,作者 Saar,点击查看 => 帖子原文
点击查看 => 来自 Microsoft Blog 的帖子
从异步更新进度想起的事儿——IProgress的更多相关文章
- android  AsyncTask异步下载并更新进度条
		
AsyncTask异步下载并更新进度条 //如果不是很明白请看上篇文章的异步下载 AsyncTask<String, Integer, String> 第一个参数:String 传入 ...
 - WPF BackGroundWord 异步加载更新进度条示例
		
<Window x:Class="AsynchronousLoading.MainWindow" xmlns="http://schemas.microsoft.c ...
 - Winform实现多线程异步更新UI(进度及状态信息)
		
引言 在进行Winform程序开发需要进行大量的数据的读写操作的时候,往往会需要一定的时间,然在这个时间段里面,界面ui得不到更新,导致在用户看来界面处于假死的状态,造成了不好的用户体验.所以在大量数 ...
 - 使用AsyncTask异步更新UI界面及原理分析
		
概述: AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类.AsyncTask的内部实现是一个线程池,所有提交的异步任务都会在这个线程池中的工作线 ...
 - Android异步处理系列文章四篇之二 使用AsyncTask异步更新UI界面
		
Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+Loope ...
 - Android  异步加载数据   AsyncTask异步更新界面
		
官方文档: AsyncTask enables proper and easy use of the UI thread. This class allows to perform backg ...
 - Android异步处理二:使用AsyncTask异步更新UI界面
		
在<Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面>中,我们使用Thread+Handler的方式实现了异步更新UI界面,这一篇中,我们介绍一种更为简 ...
 - Unity3d中制作异步Loading进度条所遇到的问题
		
背景 通常游戏的主场景包括的资源较多,这会导致载入场景的时间较长.为了避免这个问题,能够首先载入Loading场景.然后再通过Loading场景来载入主场景. 由于Loading场景包括的资源较少,所 ...
 - 【Win 10 应用开发】通过数据绑定更新进度条
		
实现 INotifyPropertyChanged 接口可以在属性更改后通知数据的使用者,这个相信大伙儿都知道.于是,有朋友会问:对于要实时显示进度的情况,比如更新进度条,能用这个实现吗? 当然是可以 ...
 
随机推荐
- Quartz.Net任务统一调度框架
			
山寨版Quartz.Net任务统一调度框架 TaskScheduler 在日常工作中,大家都会经常遇到Win服务,在我工作的这些年中一直在使用Quartz.Net这个任务统一调度框架,也非常好用, ...
 - crawler_浅谈网络爬虫
			
题记: 1024,今天是个程序猿的节日 ,哈哈,转为正题,从事了一线网络爬虫开发有近1000天.简单阐述下个人对网络爬虫的理解. 提纲: 1:是什么 2:能做什么 3:怎么做 4:综述 1:是什么 w ...
 - java-新浪微博开放平台——话题跟踪
			
代码 网盘地址:http://pan.baidu.com/s/1pJ1D0Kz
 - 【分享】小工具大智慧之Sql执行工具
			
原文:[分享]小工具大智慧之Sql执行工具 工具概况 情况是这样的,以前我们公司有很多Sql用于完成一些很不起眼但又不得不完成的业务,出于方便就直接在Sql查询分析器里执行,按理说应该写一些专门的工具 ...
 - 由于问题引起信号ORA-27154无法启动数据库
			
测试库运行startup当系统提示(11.2.0.1): 查询ORA-27154的错误: Error: ORA-27154 Text: post/wait create failed -------- ...
 - 【转】Appium 服务器端从启动到case完成的活动分析
			
原文地址:http://blog.csdn.net/zhubaitian/article/details/39474151 此文的目的主要是通过分析Appium Server打印出来的log,加深对A ...
 - 百度地图API显示多个标注点,解决提示信息问题以及给标注增加地图旁的文字连接提示的另一种解决办法
			
原文:百度地图API显示多个标注点,解决提示信息问题以及给标注增加地图旁的文字连接提示的另一种解决办法 公司的网站改版要求在一个页面显示百度地图.上面要同时显示很多标注点,标注点当然要有提示信息嘛,提 ...
 - Lucene.Net简介和分词
			
Lucene.net站内搜索—2.Lucene.Net简介和分词 2015-03-24 23:10 by 邹琼俊, 118 阅读, 1 评论, 收藏, 编辑 Lucene.Net简介 Lucene.N ...
 - 如此高效通用的分页存储过程是带有sql注入漏洞的
			
原文:如此高效通用的分页存储过程是带有sql注入漏洞的 在google中搜索“分页存储过程”会出来好多结果,是大家常用的分页存储过程,今天我却要说它是有漏洞的,而且漏洞无法通过修改存储过程进行补救,如 ...
 - SQL表连接
			
背景 在上次的自考科目<数据库系统原理>中.已经接触到了关于数据库表连接的一些知识,近期的学习过程中又用到了关于数据库表的连接问题,趁此再跟大家一起回想一下. 导图总结 首先用一张思维导图 ...