如下所示将linq 2 sql查询包装到Task.Run方法中好不好
var keywordlistquery = await Task.Run(() =>
{
using (DataContext context = new DataContext(connection))
{
context.ObjectTrackingEnabled = false;
return from keyword in context.GetTable<KeywordsList>()
select new
{
keyword.search_text,
keyword.search_keyword
};
}
});
上面的代码线程安全吗,在生产环境中会不会有任何问题?有没有其他更好的方法来编写上面的代码。
最佳答案
这里的好答案在很大程度上取决于代码的意图。
但总的来说,请记住,Linq to SQL 技术是在 .Net 中实现 native 异步和等待模式之前构建然后停止使用的。
因此,除非您非常习惯手动维护异步任务,否则最好不要尝试将异步与 Linq to SQL 一起使用。很有可能,除非期望服务器能够处理非常高级别的请求并发,否则您不会获得太多性能提升,但是手动处理异步任务是引入真正难以检测的错误的绝佳方式,这些错误最终会意外阻止请求线程。
如果您确实需要像这样在代码中处理异步,有两种解决方案。
首先了解上面的代码创建了一个查询,但没有执行它。它返回的是一个 IQuerable...基本上,可以将其视为尚未运行的 SQL 语句。 Linq to SQL 将不会运行查询,直到调用 ToArray 或 ToList 之类的方法,或者直到在 foreach 循环或类似循环中使用它。
此外,当您使用 return 语句时,像这样使用匿名类型会变得很困难。您可能需要创建 DTO 类并使用选择投影来实例化它们
其次,您将上下文包装在一个 using block 中(这是一个很好的做法),但是如果您在实际执行之前返回查询,那么上下文将被释放。调用者将获得一个 IQueryable,但当它尝试使用它时,您将以异常结束,因为上下文已被释放。
所以....这里有两个选项,具体取决于这段代码是要返回实际数据,还是只返回一个查询,调用者可以进一步修改。
案例一)返回数据:
public async Task<object> DoThings(CancellationToken token)
{
var keywordlistquery = await Task.Run(() =>
{
using (var context = new DataClasses1DataContext())
{
context.ObjectTrackingEnabled = false;
return from keyword in context.GetTable<KeywordsList>()
select new
{
keyword.search_text,
keyword.search_keyword
};
}
}, token);
return keywordlistquery;
}
请注意,方法本身应该是异步的,并且您应该尽可能尝试使用取消 token 。这会调用 ToArray 以强制查询立即执行并返回数据。请记住,这将返回整个表。如果调用者想要提供 where 子句或其他任何内容,代码仍将加载所有数据。
情况 2:返回 IQuerable
在情况 2 中,您希望您的方法只返回查询。这样,调用者可以在查询执行之前修改查询。这允许调用者添加语句以包含 where 子句或对结果进行排序等等;并将这些语句包含在生成的 TSQL 中。
在这种情况下,诀窍在于调用者必须控制数据上下文的生命周期,并且由于该方法实际上并不执行结果,因此它不需要异步。
public async Task CallingMethod()
{
using (var context = new DataClasses1DataContext())
{
var token = new CancellationToken();
context.ObjectTrackingEnabled = false;
var query = DoThings(context);
var result = await Task.Run(() => query.ToArray(), token);
}
}
public IQueryable<object> DoThings(DataContext context)
{
var keywordlistquery = from keyword in context.GetTable<KeywordsList>()
select new
{
keyword.search_text,
keyword.search_keyword
};
return keywordlistquery;
}
不过正如我之前提到的,select new anonynous 在这种情况下效果不佳。最好创建一个 DTO 类并从中选择一个新类,或者返回整个表。
关于linq-to-sql - 通过在 Task.Run() 中包装 linq 查询,在多线程中进行 linq to sql,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39016876/