如何编写异步 LINQ 查询? [英] How to write Asynchronous LINQ query?

查看:33
本文介绍了如何编写异步 LINQ 查询?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看了一堆LINQ相关的东西,突然发现没有文章介绍如何编写异步LINQ查询.

After I read a bunch of LINQ related stuff, I suddenly realized that no articles introduce how to write asynchronous LINQ query.

假设我们使用 LINQ to SQL,下面的语句很清楚.但是,如果SQL数据库响应慢,那么使用这块代码的线程就会受到阻碍.

Suppose we use LINQ to SQL, below statement is clear. However, if the SQL database responds slowly, then the thread using this block of code would be hindered.

var result = from item in Products where item.Price > 3 select item.Name;
foreach (var name in result)
{
    Console.WriteLine(name);
}

似乎当前的 LINQ 查询规范不对此提供支持.

Seems that current LINQ query spec doesn't provide support to this.

LINQ 有什么方法可以做异步编程吗?它的工作原理就像有一个回调当结果准备好使用时通知,没有任何 I/O 阻塞延迟.

Is there any way to do asynchronous programming LINQ? It works like there is a callback notification when results are ready to use without any blocking delay on I/O.

推荐答案

虽然 LINQ 本身并没有真正具有这个功能,但框架本身具有...您可以轻松地在 30 行左右的时间内推出自己的异步查询执行器...事实上,我只是为你把它放在一起:)

While LINQ doesn't really have this per se, the framework itself does... You can easily roll your own asynchronous query executor in 30 lines or so... In fact, I just threw this together for you :)

通过写这篇文章,我发现了为什么他们没有实现它.它无法处理匿名类型,因为它们是本地范围的.因此,您无法定义回调函数. 这是一件非常重要的事情,因为很多 linq 到 sql 的东西都在 select 子句中创建了它们.下面的任何一个建议都遭受同样的命运,所以我仍然认为这个是最容易使用的!

Through writing this, I've discovered why they didn't implement it. It cannot handle anonymous types since they are scoped local. Thus, you have no way of defining your callback function. This is a pretty major thing since a lot of linq to sql stuff creates them in the select clause. Any of the below suggestions suffer the same fate, so I still think this one is the easiest to use!

唯一的解决方案是不使用匿名类型.您可以将回调声明为仅采用 IEnumerable(无类型参数),并使用反射来访问字段(ICK!!).另一种方法是将回调声明为动态"......哦......等等......那还没有结束.:) 这是如何使用动态的另一个体面的例子.有些人可能称之为滥用.

The only solution is to not use anonymous types. You can declare the callback as just taking IEnumerable (no type args), and use reflection to access the fields (ICK!!). Another way would be to declare the callback as "dynamic"... oh... wait... That's not out yet. :) This is another decent example of how dynamic could be used. Some may call it abuse.

将其放入您的实用程序库:

Throw this in your utilities library:

public static class AsynchronousQueryExecutor
{
    public static void Call<T>(IEnumerable<T> query, Action<IEnumerable<T>> callback, Action<Exception> errorCallback)
    {
        Func<IEnumerable<T>, IEnumerable<T>> func =
            new Func<IEnumerable<T>, IEnumerable<T>>(InnerEnumerate<T>);
        IEnumerable<T> result = null;
        IAsyncResult ar = func.BeginInvoke(
                            query,
                            new AsyncCallback(delegate(IAsyncResult arr)
                            {
                                try
                                {
                                    result = ((Func<IEnumerable<T>, IEnumerable<T>>)((AsyncResult)arr).AsyncDelegate).EndInvoke(arr);
                                }
                                catch (Exception ex)
                                {
                                    if (errorCallback != null)
                                    {
                                        errorCallback(ex);
                                    }
                                    return;
                                }
                                //errors from inside here are the callbacks problem
                                //I think it would be confusing to report them
                                callback(result);
                            }),
                            null);
    }
    private static IEnumerable<T> InnerEnumerate<T>(IEnumerable<T> query)
    {
        foreach (var item in query) //the method hangs here while the query executes
        {
            yield return item;
        }
    }
}

你可以这样使用它:

class Program
{

    public static void Main(string[] args)
    {
        //this could be your linq query
        var qry = TestSlowLoadingEnumerable();

        //We begin the call and give it our callback delegate
        //and a delegate to an error handler
        AsynchronousQueryExecutor.Call(qry, HandleResults, HandleError);

        Console.WriteLine("Call began on seperate thread, execution continued");
        Console.ReadLine();
    }

    public static void HandleResults(IEnumerable<int> results)
    {
        //the results are available in here
        foreach (var item in results)
        {
            Console.WriteLine(item);
        }
    }

    public static void HandleError(Exception ex)
    {
        Console.WriteLine("error");
    }

    //just a sample lazy loading enumerable
    public static IEnumerable<int> TestSlowLoadingEnumerable()
    {
        Thread.Sleep(5000);
        foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 })
        {
            yield return i;
        }
    }

}

现在去把它放在我的博客上,非常方便.

Going to go put this up on my blog now, pretty handy.

这篇关于如何编写异步 LINQ 查询?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆