在这篇文章中,我们将为您详细介绍Parallel.ForeachSQL查询有时会导致连接的内容,并且讨论关于sql连接查询效率低的相关问题。此外,我们还会涉及一些关于C#Parallel.ForEac
在这篇文章中,我们将为您详细介绍Parallel.Foreach SQL查询有时会导致连接的内容,并且讨论关于sql连接查询效率低的相关问题。此外,我们还会涉及一些关于C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少、C# Parellel.For 和 Parallel.ForEach、c# – Parallel.Foreach SQL查询有时会导致连接、c# – Parallel.ForEach同时保留订单的知识,以帮助您更全面地了解这个主题。
本文目录一览:- Parallel.Foreach SQL查询有时会导致连接(sql连接查询效率低)
- C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少
- C# Parellel.For 和 Parallel.ForEach
- c# – Parallel.Foreach SQL查询有时会导致连接
- c# – Parallel.ForEach同时保留订单
Parallel.Foreach SQL查询有时会导致连接(sql连接查询效率低)
我需要加快在应用程序中执行12个查询的速度。我从常规的foreach切换到Parallel.ForEach。但是有时我会收到一条错误消息,提示“
ExecuteReader需要打开且可用的连接。连接的当前状态为连接中”。据我了解,由于12个查询中的许多查询都使用相同的InitialCatalog,因此12个查询中并没有真正的新连接,这可能是问题所在吗?我怎样才能解决这个问题?“
sql”是“ Sql”类型的列表-一个类只是一个字符串名称,字符串connectiona和一个查询列表。这是代码:
/// <summary> /// Connects to SQL, performs all queries and stores results in a list of DataTables /// </summary> /// <returns>List of data tables for each query in the config file</returns> public List<DataTable> GetAllData() { Stopwatch sw = new Stopwatch(); sw.Start(); List<DataTable> data = new List<DataTable>(); List<Sql> sql=new List<Sql>(); Sql one = new Sql(); one.connection = "Data Source=XXX-SQL1;Initial Catalog=XXXDB;Integrated Security=True"; one.name = "Col1"; one.queries.Add("SELECT Name FROM [Reports]"); one.queries.Add("SELECT Other FROM [Reports2]"); sql.Add(one); Sql two = new Sql(); two.connection = "Data Source=XXX-SQL1;Initial Catalog=XXXDB;Integrated Security=True"; two.name = "Col2"; two.queries.Add("SELECT AlternateName FROM [Reports1]"); sql.Add(two); Sql three = new Sql(); three.connection = "Data Source=YYY-SQL2;Initial Catalog=YYYDB;Integrated Security=True"; three.name = "Col3"; three.queries.Add("SELECT Frequency FROM Times"); sql.Add(three); try { // ParallelOptions options = new ParallelOptions(); //options.MaxDegreeOfParallelism = 3; // Parallel.ForEach(sql, options, s => Parallel.ForEach(sql, s => //foreach (Sql s in sql) { foreach (string q in s.queries) { using (connection = new SqlConnection(s.connection)) { connection.Open(); DataTable dt = new DataTable(); dt.TableName = s.name; command = new SqlCommand(q, connection); SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand = command; adapter.Fill(dt); //adapter.Dispose(); lock (data) { data.Add(dt); } } } } ); } catch (Exception ex) { MessageBox.Show(ex.ToString(), "GetAllData error"); } sw.Stop(); MessageBox.Show(sw.Elapsed.ToString()); return data; }
这是我需要的Sql类:
/// <summary>/// Class defines a SQL connection and its respective queries/// </summary>public class Sql{ /// <summary> /// Name of the connection/query /// </summary> public string name { get; set; } /// <summary> /// SQL Connection string /// </summary> public string connection { get; set; } /// <summary> /// List of SQL queries for a connection /// </summary> public List<string> queries = new List<string>();}
答案1
小编典典我将重构您的业务逻辑(连接到数据库)。
public class SqlOperation{ public SqlOperation() { Queries = new List<string>(); } public string TableName { get; set; } public string ConnectionString { get; set; } public List<string> Queries { get; set; }}public static List<DataTable> GetAllData(IEnumerable<SqlOperation> sql){ var taskArray = sql.SelectMany(s => s.Queries .Select(query => Task.Run(() => //Task.Factory.StartNew for .NET 4.0 ExecuteQuery(s.ConnectionString, s.TableName, query)))) .ToArray(); try { Task.WaitAll(taskArray); } catch(AggregateException e) { MessageBox.Show(e.ToString(), "GetAllData error"); } return taskArray.Where(t => !t.IsFaulted).Select(t => t.Result).ToList();}public static DataTable ExecuteQuery(string connectionString, string tableName, string query){ DataTable dataTable = null; using (var connection = new SqlConnection(connectionString)) { dataTable = new DataTable(); dataTable.TableName = tableName; using(var command = new SqlCommand(query, connection)) { connection.Open(); using(var adapter = new SqlDataAdapter()) { adapter.SelectCommand = command; adapter.Fill(dataTable); } } } return dataTable;}
C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少
有没有办法保证总是返回所有任务?
评论中的几个人指出你应该这样做,假设 numbers
是一个非线程安全列表:
foreach(var number in numbers)
{
var value = Regex.Replace(number,@"\s+","%20");
tasks.Add(client.GetAsync(url + value));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
foreach (var task in tasks)
{
...
}
并行创建下载任务似乎没有任何显着的好处;这发生得非常快。等待下载完成是在 WhenAll
ps;有多种更复杂的方法可以为 URL 转义数据,但如果您特别想将任何类型的空格转换为 %20,我想使用正则表达式来做是有意义的。
编辑;你问什么时候使用 Parallel ForEach,我会说“通常不要,因为你必须更加小心你使用它的上下文”,但是如果你让 Parallel.ForEach 做更多同步工作,这可能是有道理的:
Parallel.ForEach(numbers,number =>
{
var value = Regex.Replace(number,"%20");
var r = client.Get(url + value));
//do something meaningful with r here,i.e. whatever ... is in your foreach (var task in tasks)
});
但是请注意,如果您出于协调目的从主体内部对某些共享事物执行更新,则它需要是线程安全的
,你没有显示它,所以我们只能猜测,但我假设 tasks
是一个 List<>
。此集合类型不是线程安全的;您的并行循环可能会“覆盖”值。要么手动锁定您的列表,要么切换到线程安全的集合,例如 ConcurrentQueue<>
var tasks = new ConcurrentQueue<Task<string>>();
Parallel.ForEach(numbers,number =>
{
var value = Regex.Replace(number,"%20");
tasks.Enqueue(client.GetAsync(url + value));
});
await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false);
foreach (var task in tasks)
{
// whatever
}
也就是说,您对 Parallel.ForEach
的使用非常可疑。您没有在循环内执行任何真正重要的事情。使用 Parallel
,尤其是在适当锁定的情况下,可能会产生更高的开销,从而抵消您声称观察到的或通过并行化 Regex
调用实现的任何潜在收益。我会将其转换为普通的 foreach
循环并预编译 Regex
以抵消其(部分)开销:
// in class
private static readonly Regex SpaceRegex = new Regex(@"\s+",RegexOptions.Compiled);
// in method
var tasks = new List<Task<string>>();
foreach (var number in numbers)
{
var value = SpaceRegex.Replace(number,"%20");
tasks.Add(client.GetAsync(url + value));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
foreach (var task in tasks)
{
// whatever
}
或者,根本不使用正则表达式。使用适当的 Uri 转义机制,不仅可以修复空格,还可以带来额外的好处:
var value = Uri.EscapeDataString(number);
// or
var fullUri = Uri.EscapeUriString(url + number);
注意这里有两种不同的方法。正确使用取决于 url
和 number
的值。还有其他机制,例如 HttpUtility.UrlEncode
方法...但我认为这些是首选。
C# Parellel.For 和 Parallel.ForEach
简介:任务并行库(Task Parellel Library)是BCL的一个类库,极大的简化了并行编程。
使用任务并行库执行循环
C#当中我们一般使用for和foreach执行循环,有时候我们呢的循环结构每一次的迭代需要依赖以前一次的计算或者行为。但是有时候则不需要。如果迭代之间彼此独立,并且程序运行在多核处理器上,如果能将不同的迭代放到不同的处理器上并行处理,则会获益匪浅。Parallel.For和Parallel.ForEach就是为此而生的。
①使用Parallel.For 声明如下:
这里可以看到 toExclusive这个参数,它是不含的, 在使用的时候传入参数要注意下。
举个例子:
static void Main(string[] args)
{
Parallel.For(0, 5, i =>
{
//打印平方
Console.WriteLine("The Square of {0} is {1}", i, i * i);
}
);
Console.ReadKey();
}
执行结果:
The Square of 0 is 0
The Square of 2 is 4
The Square of 1 is 1
The Square of 4 is 16
The Square of 3 is 9
从执行结果上我们可以看到,它不是按顺序执行的。那么问题来了,怎么让结果保持有序?
我们可以通过一个数组来存储执行的结果,例如下面的例子:
static void Main(string[] args)
{
const int maxValues = 5;
int[] Squares = new int[maxValues];
Parallel.For(0, maxValues , i =>Squares[i] = i*i );
for (int i = 0; i < maxValues; i++) Console.WriteLine("Square of {0} is {1}", i, Squares[i]);
Console.ReadKey();
}
我们首先定义了一个数组,然后由于数组的下标已经定下来了,所以每次执行都会存入具体的位置,然后遍历结果的数组,就得到了有顺序的结果。
②使用Parallel.ForEach
最简单的实现,声明如下:
举例:
static void Main(string[] args)
{
string[] squares = new string[]
{"We", "hold", "these", "truths", "to", "be", "self-evident", "that", "all", "men", "are", "created", "equal"};
Parallel.ForEach(squares,
i => Console.WriteLine(string.Format("''{0}'' has {1} letters", i, i.Length)));
Console.ReadKey();
}
结果:
''We'' has 2 letters
''hold'' has 4 letters
''these'' has 5 letters
''to'' has 2 letters
''truths'' has 6 letters
''self-evident'' has 12 letters
''that'' has 4 letters
''be'' has 2 letters
''men'' has 3 letters
''are'' has 3 letters
''created'' has 7 letters
''equal'' has 5 letters
''all'' has 3 letters
这里同样可以看到,不是按顺序遍历的。
c# – Parallel.Foreach SQL查询有时会导致连接
/// <summary> /// Connects to sql,performs all queries and stores results in a list of DataTables /// </summary> /// <returns>List of data tables for each query in the config file</returns> public List<DataTable> GetAllData() { Stopwatch sw = new Stopwatch(); sw.Start(); List<DataTable> data = new List<DataTable>(); List<sql> sql=new List<sql>(); sql one = new sql(); one.connection = "Data Source=XXX-sql1;Initial Catalog=XXXDB;Integrated Security=True"; one.name = "Col1"; one.queries.Add("SELECT Name FROM [Reports]"); one.queries.Add("SELECT Other FROM [Reports2]"); sql.Add(one); sql two = new sql(); two.connection = "Data Source=XXX-sql1;Initial Catalog=XXXDB;Integrated Security=True"; two.name = "Col2"; two.queries.Add("SELECT AlternateName FROM [Reports1]"); sql.Add(two); sql three = new sql(); three.connection = "Data Source=YYY-sql2;Initial Catalog=YYYDB;Integrated Security=True"; three.name = "Col3"; three.queries.Add("SELECT Frequency FROM Times"); sql.Add(three); try { // ParallelOptions options = new ParallelOptions(); //options.MaxDegreeOfParallelism = 3; // Parallel.ForEach(sql,options,s => Parallel.ForEach(sql,s => //foreach (sql s in sql) { foreach (string q in s.queries) { using (connection = new sqlConnection(s.connection)) { connection.open(); DataTable dt = new DataTable(); dt.TableName = s.name; command = new sqlCommand(q,connection); sqlDataAdapter adapter = new sqlDataAdapter(); adapter.SelectCommand = command; adapter.Fill(dt); //adapter.dispose(); lock (data) { data.Add(dt); } } } } ); } catch (Exception ex) { MessageBox.Show(ex.ToString(),"GetAllData error"); } sw.Stop(); MessageBox.Show(sw.Elapsed.ToString()); return data; }
这是我制作的你需要的sql类:
/// <summary> /// Class defines a sql connection and its respective queries /// </summary> public class sql { /// <summary> /// Name of the connection/query /// </summary> public string name { get; set; } /// <summary> /// sql Connection string /// </summary> public string connection { get; set; } /// <summary> /// List of sql queries for a connection /// </summary> public List<string> queries = new List<string>(); }
解决方法
public class sqlOperation { public sqlOperation() { Queries = new List<string>(); } public string TableName { get; set; } public string ConnectionString { get; set; } public List<string> Queries { get; set; } } public static List<DataTable> GetAllData(IEnumerable<sqlOperation> sql) { var taskArray = sql.SelectMany(s => s.Queries .Select(query => Task.Run(() => //Task.Factory.StartNew for .NET 4.0 ExecuteQuery(s.ConnectionString,s.TableName,query)))) .ToArray(); try { Task.WaitAll(taskArray); } catch(AggregateException e) { MessageBox.Show(e.ToString(),"GetAllData error"); } return taskArray.Where(t => !t.IsFaulted).Select(t => t.Result).ToList(); } public static DataTable ExecuteQuery(string connectionString,string tableName,string query) { DataTable dataTable = null; using (var connection = new sqlConnection(connectionString)) { dataTable = new DataTable(); dataTable.TableName = tableName; using(var command = new sqlCommand(query,connection)) { connection.open(); using(var adapter = new sqlDataAdapter()) { adapter.SelectCommand = command; adapter.Fill(dataTable); } } } return dataTable; }
c# – Parallel.ForEach同时保留订单
如果没有,任何想法如何实现同步运行这一切的加速?
谢谢
解决方法
如果是这样,是的,操作很简单.不要理会锁定或同步构造,这些会侵蚀并行化带给您的所有速度.
相反,如果遵守这个简单的规则,任何算法都可以并行化,而无需锁定或同步:
For each input element X[i] processed,you may read from any input element X[j],but only write to output element Y[i]
查找Scatter / Gather,这种类型的操作称为聚集,因为只写入一个输出元素.
如果你可以使用上面的原则,那么你想要在前面创建输出数组Foo [],并在输入数组上使用Parallel.For not ForEach.
例如.
List<byte[]> inputArray = new List<byte[]>(); int[] outputArray = new int[inputArray.Count]; var waitHandle = new ManualResetEvent(false); int counter = 0; Parallel.For(0,inputArray.Count,index => { // Pass index to for loop,do long running operation // on input items // writing to only a single output item outputArray[index] = DoOperation(inputArray[index]); if(Interlocked.Increment(ref counter) == inputArray.Count -1) { waitHandle.Set(); } }); waitHandler.WaitOne(); // Optional conversion back to list if you wanted this var outputList = outputArray.ToList();
关于Parallel.Foreach SQL查询有时会导致连接和sql连接查询效率低的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少、C# Parellel.For 和 Parallel.ForEach、c# – Parallel.Foreach SQL查询有时会导致连接、c# – Parallel.ForEach同时保留订单等相关知识的信息别忘了在本站进行查找喔。
本文标签: