【WP8】同步执行异步代码

微软的StorageFile只支持异步的方式进行文件操作,我之前也封装过一个StorageHelper,但是当所有的方法都是异步的时候也带来一些问题

  1、比如我们不能在构造函数调用异步代码(等待),

  2、比如我们在离开App的时候我们需要对数据进行快速的保存(在事件中),这个时候就不适合用异步了,异步可能会导致保存失败,因为App已经不在前台了

最近就遇到了一个这样的需求

  我封装了一个SqliteHelper类,提供了一些数据库操作的一些常用方法,在数据库使用之前,需要保证数据库路径的文件夹是存在的,如果不能存在,则会抛出异常,所以在SqliteHelper的构造函数判断该文件夹是否存在,如果不存在,则创建该文件夹,但是StorageHelper不支持同步方法(这里不使用IsolatedStorage),我们需要保证在StorageHelper在构造完成时,保证文件夹存在

    public SqliteHelper(string dbPath)
    {
        this.dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, dbPath);
        var directory = Path.GetDirectoryName(dbPath);
        if (directory != null)
        {
            //TODO:构造函数不支持await关键字
            //await StorageHelper.Instance.CreateDirectoryAsync(directory);
        }
    }

  满足上面需求可以有两个方法:

  1、通过一个静态异步方法来构造SqliteHelper的实例,把异步操作放到异步方法里面,但是这种方法会导致不能使用依赖注入IoC

    private SqliteHelper(string dbPath)
    {
        this.dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, dbPath);
    }

    public static async Task<SqliteHelper> GetSqliteHelper(string dbPath)
    {
        var sqliteHelper = new SqliteHelper(dbPath);
        var directory = Path.GetDirectoryName(dbPath);
        if (directory != null)
        {
            await StorageHelper.Instance.CreateDirectoryAsync(directory);
        }
        return sqliteHelper;
    }

  2、让异步方法同步执行

    我们首先定义一个异步执行Helper,提供异步方法的同步(摘自后面的参考文章)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestDemo
{
    public static class AsyncInline
    {
        public static void Run(Func<Task> item)
        {
            var oldContext = SynchronizationContext.Current;
            var synch = new ExclusiveSynchronizationContext();
            SynchronizationContext.SetSynchronizationContext(synch);
            synch.Post(async _ =>
            {
                try
                {
                    await item();
                }
                catch (Exception e)
                {
                    synch.InnerException = e;
                    throw;
                }
                finally
                {
                    synch.EndMessageLoop();
                }
            }, null);
            synch.BeginMessageLoop();
            SynchronizationContext.SetSynchronizationContext(oldContext);
        }
        public static T Run<T>(Func<Task<T>> item)
        {
            var oldContext = SynchronizationContext.Current;
            var synch = new ExclusiveSynchronizationContext();
            SynchronizationContext.SetSynchronizationContext(synch);
            T ret = default(T);
            synch.Post(async _ =>
            {
                try
                {
                    ret = await
                    item();
                }
                catch (Exception e)
                {
                    synch.InnerException = e;
                    throw;
                }
                finally
                {
                    synch.EndMessageLoop();
                }
            }, null);
            synch.BeginMessageLoop();
            SynchronizationContext.SetSynchronizationContext(oldContext);
            return ret;
        }

        private class ExclusiveSynchronizationContext : SynchronizationContext
        {
            private bool done;
            public Exception InnerException { get; set; }
            readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
            readonly Queue<Tuple<SendOrPostCallback, object>> items =
             new Queue<Tuple<SendOrPostCallback, object>>();

            public override void Send(SendOrPostCallback d, object state)
            {
                throw new NotSupportedException("We cannot send to our same thread");
            }
            public override void Post(SendOrPostCallback d, object state)
            {
                lock (items)
                {
                    items.Enqueue(Tuple.Create(d, state));
                }
                workItemsWaiting.Set();
            }
            public void EndMessageLoop()
            {
                Post(_ => done = true, null);
            }
            public void BeginMessageLoop()
            {
                while (!done)
                {
                    Tuple<SendOrPostCallback, object> task = null;
                    lock (items)
                    {
                        if (items.Count > 0)
                        {
                            task = items.Dequeue();
                        }
                    }
                    if (task != null)
                    {
                        task.Item1(task.Item2);
                        if (InnerException != null) // the method threw an exeption
                        {
                            throw new AggregateException("AsyncInline.Run method threw an exception.",
                             InnerException);
                        }
                    }
                    else
                    {
                        workItemsWaiting.WaitOne();
                    }
                }
            }
            public override SynchronizationContext CreateCopy()
            {
                return this;
            }
        }
    }
}

    接下来我们就可以像同步方法一样使用异步方法了

    public class TestClass
    {
        public int Id { get; set; }

        public TestClass()
        {
            //这里调用一个异步方法,等待异步方法执行返回
            Id = AsyncInline.Run(GetIdAsync);

            //不支持await
            //await GetIdAsync();
        }

        /// <summary>
        /// 异步方法
        /// </summary>
        public async Task<int> GetIdAsync()
        {
            //TODO:这里执行模拟自定义操作
            await Task.Delay(1000);

            return 10;
        }
    }

参考文章:

  http://social.msdn.microsoft.com/Forums/en-US/163ef755-ff7b-4ea5-b226-bbe8ef5f4796/is-there-a-pattern-for-calling-an-async-method-synchronously?forum=async

  http://stackoverflow.com/questions/8145479/can-constructors-be-async

个人能力有限,如果有更好的实现,可以给我留言

转载请注明出处:http://www.cnblogs.com/bomo/p/3942750.html

时间: 2024-10-09 12:57:48

【WP8】同步执行异步代码的相关文章

node.js的作用、回调、同步异步代码、事件循环

http://www.nodeclass.com/articles/39274 一.node.js的作用 I/O的意义,(I/O是输入/输出的简写,如:键盘敲入文本,输入,屏幕上看到文本显示输出.鼠标移动,在屏幕上看到鼠标的移动.终端的输入,和看到的输出.等等) node.js想解决的问题,(处理输入,输入,高并发 .如 在线游戏中可能会有上百万个游戏者,则有上百万的输入等等)(node.js适合的范畴:当应用程序需要在网络上发送和接收数据时Node.js最为适合.这可能是第三方的API,联网设

使用ES6 +Promise组织异步代码

(1)为什么要使用promise这种设计模式,这种设计模式的好处是什么 解决 JavaScript 异步事件的传统方式是回调函数:调用一个方法,然后给它一个函数引用,当这个方法完结的时候执行这个函数引用. Javascript 中的神器--Promise Promise in js 回调函数真正的问题在于他剥夺了我们使用 return 和 throw 这些关键字的能力.而 Promise 很好地解决了这一切. 2015 年 6 月,ECMAScript 6 的正式版 终于发布了. ECMAScr

Ajax同步、异步和相应数据格式

(一)同步和异步 xhr.open()方法第三个参数要求传入的是一个 布尔值,其作用就是设置此次请求是否采用异步方式执行 默认为 true异步 可修改为 false为同步. 异步代码举栗: 1 console.log('before ajax') 2 var xhr = new XMLHttpRequest() 3 // 默认第三个参数为 true 意味着采用异步方式执行 4 xhr.open('GET', '/time', true) 5 xhr.send(null) 6 xhr.onread

IOS多线程知识总结/队列概念/GCD/主队列/并行队列/全局队列/主队列/串行队列/同步任务/异步任务区别(附代码)

进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每一个进程都有自己独立的虚拟内存空间 线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程 队列 dispatch_queue_t,队列名称在调试时辅助,无论什么队列和任务,线程的创建和回收不需要程序员操作,有队列负责. 串行队列:队列中的任务只会顺序执行(类似跑步) dispatch_queue_t q = dispatch_queue_create(“....”, DISPATCH_QUEUE_SER

一个例子看懂异步代码执行效率

异步代码采用线程池,提供代码执行的并行性,不阻塞当前线程,实例代码,模拟三个耗时操作,分别耗时为1000.1500.1800ms,提供同步与异步的实现方式,Main中以同步异步的方式执行,对比执行时间,同步执行方式为各个方法的执行时间总和,而异步执行方式为最长的那个时间.ps:实际执行情况可能有其他的一些微不足道开销,但大体能反应异步的执行效率. class OutHelper { public DateTime Method1() { Thread.Sleep(1000); return Da

ajax同步、异步执行简单理解与证明

此理解范例代码来自前几篇随笔! 重在实际操作练习一下!!!!! 在$.ajax()中我们可以常常看到async,这就是来指定ajax同步异步的,需要记忆一下: 记忆方法: sync英语中的意思是:“同步”.“同步的”.“同步处理” 前面加个“a”,构成async英文中的意思是:“异步” 再者给他指定true和false那就容易理解了: “async:true” 意思是:“异步” “async:false” 意思是:“同步” 分析async作用: 当“async:true”时,也就是异步执行aja

Adobe AIR中使用Flex连接Sqlite数据库(1)(创建数据库和表,以及同步和异步执行模式)

系列文章导航 Adobe AIR中使用Flex连接Sqlite数据库(1)(创建数据库和表) Adobe AIR中使用Flex连接Sqlite数据库(2)(添加,删除,修改以及语句参数) Adobe AIR中使用Flex连接Sqlite数据库(3)(查询) Adobe AIR中使用Flex连接Sqlite数据库(4)(事务) Flex,Fms3相关文章索引 Fms3和Flex打造在线多人视频会议和视频聊天(附原代码) 免费美女视频聊天,多人视频会议功能加强版本(Fms3和Flex开发(附源码))

同步执行与异步执行

计算机程序执行分为同步执行和异步执行 (1)同步执行 所谓的同步执行,就是正常的计算机程序执行的3大顺序流程: 顺序控制语句:从上至下,从左至右 分支控制语句:if,switch 循环控制语句:for(),while,do...while,for...in,forEach() (2)异步执行 所谓的异步执行,是一种特殊的程序的执行方式: setInterval(定时器),setTimeout(延时器) 事件的绑定 onclick,onopen,onscroll... ajax请求 (3)同步执行

GCD网络多线程---同步执行,异步执行,串行队列,并行队列

总结:同步(不管是串行还是并行)----不开辟子线程 异步(不管是串行还是并行)----开辟子线程 GCD: dispatch queue 主线程的main queue 并行队列 global dispatch queue 串行队列serial queues 一般用于按顺序同步访问 #pragma mark - 加载多线程 - (void) _loadMutil { //GCD基于C语言 //1.主对列:(串行队列) dispatch_queue_t mainQueue=dispatch_get