将 async/await 与 DataReader 一起使用? (没有中间缓冲区!)

2024-02-11

我的目标很简单,我想做异步 I/O 调用(使用 async wait) - 但是:

  • 不使用 DataFlow 依赖项(就像这个答案一样 https://stackoverflow.com/a/13148683/859154)
  • 没有中间缓冲区(不喜欢这个答案 https://stackoverflow.com/a/13148683/859154)
  • Projector 函数应作为参数发送。 (不喜欢这个答案 https://stackoverflow.com/a/13149492/859154)

Ok.

目前这是我的代码,它的工作是从数据库读取并将每一行投影到Func<>

public IEnumerable < T > GetSomeData < T > (string sql, Func < IDataRecord, T > projector)
{
    using(SqlConnection _conn = new SqlConnection(@"Data Source=..."))
    {
        using(SqlCommand _cmd = new SqlCommand(sql, _conn))
        {
            _conn.Open();
            _cmd.CommandTimeout = 100000;
            using(IDataReader rdr = _cmd.ExecuteReader())
            {
                while (rdr.Read())  yield    return projector(rdr);
            }
        }
    }
}

那么,什么是投影仪?

每个类都有一个函数,它得到一个record ( IDataRecord)并创建一个实体:

例子 :

public class MyClass
{
    public static MyClass MyClassFactory(IDataRecord record)
    {
        return new MyClass
        {
            Name = record["Name"].ToString(),
            Datee = DateTime.Parse(record["Datee"].ToString()),
            val = decimal.Parse(record["val"].ToString())
        };
    }
    public string Name    {   get;   set;  }
    public DateTime Datee    {  get;     set;  }
    public decimal val    {  get;    set;    }
}

所以在这里 ,MyClassFactory将是Func

那么我目前如何运行它呢?

 var sql = @"SELECT TOP 1000 [NAME],[datee] ,[val]  FROM [WebERP].[dbo].[t]";
 var a = GetSomeData < MyClass > (sql, MyClass.MyClassFactory).Where(...); //notice the Func

All ok.

问题现在开始:

Adding async该方法会产生错误:( 是的,我知道 Ienumerable 是一个同步接口因此出现问题)

public async Task<IEnumerable < T >> GetSomeData < T > (string sql, Func < IDataRecord, T > projector)

不能是迭代器块,因为 '系统.线程.任务.任务>' 不是迭代器接口类型

但这里的这个人却做到了 https://stackoverflow.com/a/13149492/859154 - :

Which DOES编译。

Question

我怎样才能转换my code支持完全异步IO调用?

(在条件下:没有数据流依赖,发送投影仪函数作为参数,没有中间缓冲区)


我想做异步 I/O 调用(使用异步等待) - 但是:

  • 不使用 DataFlow 依赖项(如本答案所示)
  • 没有中间缓冲区(不像这个答案)
  • Projector 函数应作为参数发送。 (不喜欢这个答案)

您可能想查看 Stephen Toub 的“任务、Monad 和 LINQ” http://blogs.msdn.com/b/pfxteam/archive/2013/04/03/tasks-monads-and-linq.aspx有关如何处理异步数据序列的一些好主意。

(尚)不可能合并yield and await,但我要在这里做一个口头表达者:引用的要求没有列出IEnumerable和 LINQ。因此,这是一个可能的解决方案,形状为两个协程(几乎未经测试)。

数据生成例程(对应于IEnumarable with yield):

public async Task GetSomeDataAsync<T>(
    string sql, Func<IDataRecord, T> projector, ProducerConsumerHub<T> hub)
{
    using (SqlConnection _conn = new SqlConnection(@"Data Source=..."))
    {
        using (SqlCommand _cmd = new SqlCommand(sql, _conn))
        {
            await _conn.OpenAsync();
            _cmd.CommandTimeout = 100000;
            using (var rdr = await _cmd.ExecuteReaderAsync())
            {
                while (await rdr.ReadAsync())
                    await hub.ProduceAsync(projector(rdr));
            }
        }
    }
}

数据消费者例程(对应于foreach或 LINQ 表达式):

public async Task ConsumeSomeDataAsync(string sql)
{
    var hub = new ProducerConsumerHub<IDataRecord>();
    var producerTask = GetSomeDataAsync(sql, rdr => rdr, hub);

    while (true)
    {
        var nextItemTask = hub.ConsumeAsync();
        await Task.WhenAny(producerTask, nextItemTask);

        if (nextItemTask.IsCompleted)
        {
            // process the next data item
            Console.WriteLine(await nextItemTask);
        }

        if (producerTask.IsCompleted)
        {
            // process the end of sequence
            await producerTask;
            break;
        }
    }
}

协程执行助手(也可以实现为一对定制服务员 http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115642.aspx):

public class ProducerConsumerHub<T>
{
    TaskCompletionSource<Empty> _consumer = new TaskCompletionSource<Empty>();
    TaskCompletionSource<T> _producer = new TaskCompletionSource<T>();

    // TODO: make thread-safe
    public async Task ProduceAsync(T data)
    {
        _producer.SetResult(data);
        await _consumer.Task;
        _consumer = new TaskCompletionSource<Empty>();
    }

    public async Task<T> ConsumeAsync()
    {
        var data = await _producer.Task;
        _producer = new TaskCompletionSource<T>();
        _consumer.SetResult(Empty.Value);
        return data;
    }

    struct Empty { public static readonly Empty Value = default(Empty); }
}

这只是一个想法。对于像这样的简单任务来说,这可能有点大材小用,并且可以在某些方面进行改进(例如线程安全、竞争条件以及在不接触序列的情况下处理序列的结尾)producerTask)。然而,它说明了异步数据检索和处理如何可能解耦。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 async/await 与 DataReader 一起使用? (没有中间缓冲区!) 的相关文章

随机推荐

  • 如何使用 GTK+ / Cairo 旋转图像

    我有一个简单的应用程序 应该使用每 x 毫秒旋转装饰轮这么多度GTK and Cairo 我下面有一些代码可以调用cairo rotate 来自计时器 然而 图像并没有改变 我是否必须使图像无效才能引发暴露事件 我对开罗很陌生 一个简单的例
  • Android SDK与ubuntu设置代理

    在哪里可以找到 android SDK 代理设置 我正在使用 ubuntu 提前致谢 我所拥有的一切都在下面的屏幕中 我目前只能在我的 mac 上查看 设置存储在 android androidtool cfg 我的设置目前如下所示 Set
  • 检查断点处的条件时 gdb 失败

    我定义一个断点 b foo 124 if strcmp bar foo getName abc 0 但是 gdb 失败并出现以下错误 Thread 0x7fffe8ef9700 LWP 25817 exited Switching to T
  • 如何让用户使用 Android 中的 Intent 仅选择本地文件?

    我需要让用户从本地存储中为我的应用程序选择一个文件 现在我正在使用INTENT ACTION GET CONTENT让用户选择文件 但它也提供了从云中选择 URI 的选项 获取 URI 文件后 我将其视为本地文件并执行各种操作 包括提取文件
  • 将组合框显示文本设置为 ObservableCollection 的属性

    我有以下集合 我想将其绑定到组合框 public ObservableCollection
  • 使用 jquery.each() 循环创建对象键

    我正在 javascript 中创建一个命名空间来循环遍历表单并创建一个对象 调用该函数的目标是循环遍历所有特定表单类型并构造一个对象 该对象的键是 html 输入的名称 值是其当前值 但是 它始终返回未定义 任何帮助将不胜感激 get f
  • 尽管符号存在,但 CMake 中的符号查找失败

    我正在尝试使用 CMake 检查符号 getaddrinfo a 是否存在 list APPEND CMAKE REQUIRED DEFINITIONS D GNU SOURCE check symbol exists getaddrinf
  • 如何用C++扩展TCL?

    我可以编写可编译并用于扩展 TCL 的 C 代码 我不是指调用可执行文件 吗 我可以描述一些类 函数并通过调用已编译的 so 或 a 文件 C 代码在我的 TCl 代码中使用它们吗 如果是 请示意性地向我解释一下它是如何完成的 http c
  • CodeFirst 相对于 Database First 的优势是什么?

    我正在观看 EF 4 1 的一些视频和教程 我不明白 CodeFirst 的任何好处 除了一些 DB 非常小的 3 4 个表并且我懒得先创建 DB 的情况 大多数情况下 迄今为止最好的方法是在某种数据库编辑器中创建数据库 这肯定比在实体模型
  • Python:如何用常规属性替换属性?

    基类有这样的 def management form self code here return form management form property management form 在我的派生类中 我试图这样写 self manag
  • CSS无冲突样式

    创建 CSS 样式表的无冲突版本的好方法是什么 假设您有一堆代码 其中的类与 Bootstrap 的类重叠 这是否有效 添加一个class bootstrap 到应应用引导样式的祖先元素 然后更改bootstrap css为每个添加前缀ru
  • JXA:从 CoreServices 访问 CFString 常量

    JXA https developer apple com library mac releasenotes InterapplicationCommunication RN JavaScriptForAutomation Articles
  • XML 数据类型方法“value”的参数 1 必须是字符串文字

    我已经读过SO XML 数据类型方法 值 必须是字符串文字 https stackoverflow com q 11029674 62576但我的问题有点不同 我在一个变量中有一些 xml 我想将其分开并给出一个路径 最初我尝试过这个 de
  • 带有组的pivot_longer并删除列名前缀[重复]

    这个问题在这里已经有答案了 我正在尝试使用pivot longer 将数据帧从宽格式转换为长格式 原始数据框是 df start lt structure list amprise 0 015 ampfull 0 005 ampfall 0
  • 桶的索引计数

    所以 这是我的小问题 Let s say I have a list of buckets a0 an which respectively contain L lt c0 cn lt H items I can decide of the
  • 使用 tastypie 的 REST url

    我在 django 应用程序中使用 tastypie 并尝试让它映射像 api booking 2011 01 01 这样的 URL 该 URL 映射到 URL 中具有指定时间戳的 Booking 模型 该文档没有说明如何实现这一点 您想要
  • 如何在离开用户界面状态时停止 $interval?

    Angular UI 路由器 在状态控制器中使用 interval 如下所示 scope Timer null scope startTimer function scope Timer interval scope Foo 30000 s
  • 使用 cmd.exe /c 相对于根本不使用 cmd 的优点

    如果我在 C 中运行一个进程 使用 cmd c 比直接运行进程有什么好处吗 Ex ProcessStartInfo info new ProcessStartInfo cmd exe info Arguments c application
  • 区分键盘的真实按键和虚拟按键

    我正在用 C 编写一个程序 它必须模拟键盘的按键命令 问题是 我需要模拟 真实 的键盘按钮点击 而不是假的 例如 据我了解 当用户按下键盘上的任何按钮时 信号通过 USB 发送 然后通过键盘驱动程序继续 当使用 API SendInput
  • 将 async/await 与 DataReader 一起使用? (没有中间缓冲区!)

    我的目标很简单 我想做异步 I O 调用 使用 async wait 但是 不使用 DataFlow 依赖项 就像这个答案一样 https stackoverflow com a 13148683 859154 没有中间缓冲区 不喜欢这个答