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

查看:121
本文介绍了如何编写异步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到SQL,下面的语句是明确的。但是,如果在SQL数据库响应缓慢,然后使用$ C $的c此块的线程将受到阻碍。

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 :)

编辑:通过写这个,我发现他们为什么没有实现它。因为它们的作用域本地它不能处理匿名类型。因此,你有没有定义回调函数的方式。这是一个pretty重要的事情,因为很多的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.

抛出这个:

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;
        }
    }

}

会去,现在把这个在我的博客,pretty派上用场了。

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

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

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