惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Vulnerabilities – Threatpost
有赞技术团队
有赞技术团队
小众软件
小众软件
O
OpenAI News
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
MongoDB | Blog
MongoDB | Blog
阮一峰的网络日志
阮一峰的网络日志
Hacker News: Ask HN
Hacker News: Ask HN
D
Docker
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
A
About on SuperTechFans
Stack Overflow Blog
Stack Overflow Blog
C
CERT Recently Published Vulnerability Notes
L
LINUX DO - 最新话题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Blog — PlanetScale
Blog — PlanetScale
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Hacker News - Newest:
Hacker News - Newest: "LLM"
G
Google Developers Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
GRAHAM CLULEY
S
Schneier on Security
T
Tor Project blog
Spread Privacy
Spread Privacy
PCI Perspectives
PCI Perspectives
Microsoft Security Blog
Microsoft Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Fortinet All Blogs
L
Lohrmann on Cybersecurity
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
The Exploit Database - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
Apple Machine Learning Research
Apple Machine Learning Research
T
Threat Research - Cisco Blogs
T
Troy Hunt's Blog
罗磊的独立博客

博客园 - xiaosonl

学习手札#3 NHibernate缓存 产品的简单性 关于过度设计的思考(上) 让ASP.NET MVC的Controller输出不同类型数据 学习手札#2 故事点和小时数的思考 学习笔记#1 键值对数据库 SQLite数据迁移 探讨一种在Silverlight不普及情况下的部署策略 有用的文档 Silverlight产品布署策略 代码的注释 下半年要看完消化的技术类书籍 中小型企业的人员流失 谈谈Ruby On Rails和ASP.NET 工作中的系统学习 Uml中的关联与依赖关系 TDD与重构设计 C#中使用位运算来实现权限管理 Silverlight中JavaSciprt无法访问托管类抽象成员的解决方法
探讨一种Silverlight的异步编程模式
xiaosonl · 2010-03-27 · via 博客园 - xiaosonl

2010-03-27 16:14  xiaosonl  阅读(1030)  评论()    收藏  举报

在开发RIA程序时,处理异步操作是个挺麻烦的问题,尤其是串行的异步调用,经常代码会写的嵌套好几层。之前老赵也介绍过一种方法来简化异步操作。我这是另一种思路。

在之前的Silverlight程序开发过程中,我的编程模式是这样的:

  1. 用户执行一个UI操作,并引发UI事件,此时在UI线程开始执行后台代码。
  2. 在代码执行过程中,遇到需要异步的操作,如网络请求等,就在另一个线程执行该操作,执行完毕后利用事件或委托继续执行接下来的操作。如果这时异步操作比较多,就会有很多的事件或委托跳来跳去的,很不好看。

这时我们可以换一种思路,反过来做,每一次的操作,我们都发起一个新的线程来执行,不再从UI线程发起。执行过程中遇到的异步操作(网格请求,或者UI操作,因为这时UI有关的操作都必须使用BeginInvoke来调用),可以用ResetEvent来阻塞住发起操作的线程,异步操作执行结束后再继续 因为一开始是在非UI线程中发起操作,所以不会阻塞UI。

总结一下:

  1. 每个操作都是发起一个新的线程来执行。
  2. 每个异步方法都可以用ResetEvent来模拟成同步方法,就可以很方便像同步方法那样调用和组织, 但在简单的异步场景中优势不明显。
  3. 缺点是影响性能,用性能来换代码的可读性和可维护性。

最后附上一个简易示例代码(未经运行测试和优化),演示将[下载数据 => 处理数据并更新UI] 的过程模拟成同步操作:

代码

    public partial class MainPage : UserControl
    {
        
public MainPage()
        {
            InitializeComponent();
        }
private void btnCommand_Click(object sender, RoutedEventArgs e)
        {
            Command();
        }
//执行操作
        public void Command()
       {
            ThreadPool.QueueUserWorkItem(t 
=>
            {
                UIInvoke(() 
=>
                { 
                    
//弹出一个ProgressBar,提示操作正在进行中
                  });//下载数据
                string downloadData = DownLoad();
                
//更新UI
                UIInvoke(() => txtMessage.Text = downloadData);

                UIInvoke(() 

=>
                {
                    
//关闭ProgressBar,提示操作结束
                });
            });
        }
//以同步的方式调用UI线程执行一个操作
        private void UIInvoke(Action action)
       {
            Dispatcher dispatcher 
= Deployment.Current.Dispatcher;if (dispatcher.CheckAccess())
            {
                action();
            }
            
else
            {
                ManualResetEvent resetEvent 
= new ManualResetEvent(false);
                resetEvent.Reset();
                dispatcher.BeginInvoke(() 
=>
                {
                    action();
                    resetEvent.Set();
                });
                resetEvent.WaitOne();
            }
        }
private string DownLoad()
        {
            ManualResetEvent reset 
= new ManualResetEvent(false);
            reset.Reset();
            
//下载数据
            WebClient client = new WebClient();
            
string result = "";
            client.DownloadStringCompleted 
+= (s, e) =>
            {
                result 
= e.Result;
                reset.Set();
            };
            client.DownloadStringAsync(
new Uri("http://下载地址"));
            reset.WaitOne();
return result;
        }
    }