Blog for something
peterluo / blog Goto Github PK
View Code? Open in Web Editor NEWBlog
Blog
在嵌套循环中,最有可能发生过度并行化的情况。 在多数情况下,除非满足以下一个或多个条件,否则最好仅对外部循环进行并行化:
已经知道内部循环非常长。
您正在每张订单上执行开销极大的计算。 (示例中所示的操作开销不大。)
已经知道目标系统具有足够的处理器来处理通过对 cust.Orders 查询进行并行化所产生的线程数。
Parallel.For循环
Parallel.For(0, source.Length, (i, loopState) =>
{
// Take the first 100 values that are retrieved
// from anywhere in the source.
if (i < 100)
{
// Accessing shared object on each iteration
// is not efficient. See remarks.
double d = Compute(source[i]);
results.Push(d);
}
else
{
loopState.Stop();
return;
}
} // Close lambda expression.
); // Close Parallel.For
Parallel.Foreach循环
Parallel.ForEach(Collection, item =>
{
//Todo
}
停止或者中断Parallel.For循环
Parallel.For(0, source.Length, (i, loopState) =>
{
// Take the first 100 values that are retrieved
// from anywhere in the source.
if (i < 100)
{
// Accessing shared object on each iteration
// is not efficient. See remarks.
double d = Compute(source[i]);
results.Push(d);
}
else
{
loopState.Stop();
return;
}
} // Close lambda expression.
); // Close Parallel.For
Parallel.For(0, source.Length, (i, loopState) =>
{
double d = Compute(source[i]);
results.Push(d);
if (d > .2)
{
// Might be called more than once!
loopState.Break();
Console.WriteLine("Break called at iteration {0}. d = {1} ", i, d);
Thread.Sleep(1000);
}
});
具有本地变量的Parallel.For循环
class Test
{
static void Main()
{
int[] nums = Enumerable.Range(0, 1000000).ToArray();
long total = 0;
// Use type parameter to make subtotal a long, not an int
Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
{
subtotal += nums[j];
return subtotal;
},
(x) => Interlocked.Add(ref total, x)
);
Console.WriteLine("The total is {0}", total);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
IntelliSense 显示其类型为 Func<int, ParallelLoopState, long, long> 或 Func(Of Integer, ParallelLoopState, Long, Long)。
lambda 表达式按对应于这些类型的相同顺序需要三个输入参数。 最后一个类型参数是返回类型。 在这种情况下,类型为 long,因为该类型是我们在For类型参数中指定的类型。 我们在 lambda 表达式中调用该变量subtotal,并将其返回。返回值用于在每个后续的迭代上初始化小计。
您也可以将此最后一个参数简单地看作传递到每个迭代,然后在最后一个迭代完成时传递到 localFinally 委托的值。
具有本地变量的Parallel.Foreach循环
static void Main()
{
int[] nums = Enumerable.Range(0, 1000000).ToArray();
long total = 0;
// First type parameter is the type of the source elements
// Second type parameter is the type of the local data (subtotal)
Parallel.ForEach<int, long>(nums, // source collection
() => 0, // method to initialize the local variable
(j, loop, subtotal) => // method invoked by the loop on each iteration
{
subtotal += nums[j]; //modify local variable
return subtotal; // value to be passed to next iteration
},
// Method to be executed when all loops have completed.
// finalResult is the final value of subtotal. supplied by the ForEach method.
(finalResult) => Interlocked.Add(ref total, finalResult)
);
Console.WriteLine("The total from Parallel.ForEach is {0}", total);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
若要在 ForEach 循环中使用线程本地变量,您必须使用采用两个 type 参数的方法版本。 第一个参数指定源元素的类型,第二个参数指定线程本地变量的类型。
第一个输入参数是数据源,第二个输入参数是对线程本地变量进行初始化的函数。 第三个输入参数是 Func<T1, T2, T3, TResult>,每个迭代上的并行循环将调用该参数。 您为委托提供代码,并且循环将传入输入参数。 输入参数为当前元素、一个使您能够检查循环状态的 ParallelLoopState 变量,以及线程本地变量。 您返回线程本地变量,方法随后会将其传递到此分区上的下一个迭代。 此变量在所有循环分区上都不同。
ForEach 方法的最后一个输入参数是 Action 委托,当所有循环完成时,方法将调用该委托。 方法为此线程(或循环分区)提供线程本地变量的最终值,并且您提供代码,该代码捕获最终值,并执行将此分区中的结果和其他分区中的结果进行合并所需的>任何操作。 由于委托类型为 Action,因此没有返回值。
取消 Parallel.For 或 ForEach Loop
namespace CancelParallelLoops
{
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
int[] nums = Enumerable.Range(0, 10000000).ToArray();
CancellationTokenSource cts = new CancellationTokenSource();
// Use ParallelOptions instance to store the CancellationToken
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
Console.WriteLine("Press any key to start. Press 'c' to cancel.");
Console.ReadKey();
// Run a task so that we can cancel from another thread.
Task.Factory.StartNew(() =>
{
if (Console.ReadKey().KeyChar == 'c')
cts.Cancel();
Console.WriteLine("press any key to exit");
});
try
{
Parallel.ForEach(nums, po, (num) =>
{
double d = Math.Sqrt(num);
Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
po.CancellationToken.ThrowIfCancellationRequested();
});
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey();
}
}
}
延续任务
// The antecedent task. Can also be created with Task.Factory.StartNew.
Task<DayOfWeek> taskA = new Task<DayOfWeek>(() => DateTime.Today.DayOfWeek);
// The continuation. Its delegate takes the antecedent task
// as an argument and can return a different type.
Task<string> continuation = taskA.ContinueWith((antecedent) =>
{
return String.Format("Today is {0}.",
antecedent.Result);
});
// Start the antecedent.
taskA.Start();
// Use the contuation's result.
Console.WriteLine(continuation.Result);
Console.Read();
已附加和已分离的子任务
分离的子任务
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var parent = Task.Factory.StartNew(() => {
Console.WriteLine("Outer task executing.");
var child = Task.Factory.StartNew(() => {
Console.WriteLine("Nested task starting.");
Thread.SpinWait(500000);
Console.WriteLine("Nested task completing.");
});
});
parent.Wait();
Console.WriteLine("Outer has completed.");
}
}
// The example produces output like the following:
// Outer task executing.
// Nested task starting.
// Outer has completed.
// Nested task completing.
附加的子任务
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var parent = Task.Factory.StartNew(() => {
Console.WriteLine("Parent task executing.");
var child = Task.Factory.StartNew(() => {
Console.WriteLine("Attached child starting.");
Thread.SpinWait(5000000);
Console.WriteLine("Attached child completing.");
}, TaskCreationOptions.AttachedToParent);
});
parent.Wait();
Console.WriteLine("Parent has completed.");
}
}
// The example displays the following output:
// Parent task executing.
// Attached child starting.
// Attached child completing.
// Parent has completed.
使用Parallel.Invoke来执行并行任务
namespace ParallelTasks
{
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
class ParallelInvoke
{
static void Main()
{
// Retrieve Darwin's "Origin of the Species" from Gutenberg.org.
string[] words = CreateWordArray(@"http://www.gutenberg.org/files/2009/2009.txt");
#region ParallelTasks
// Perform three tasks in parallel on the source array
Parallel.Invoke(() =>
{
Console.WriteLine("Begin first task...");
GetLongestWord(words);
}, // close first Action
() =>
{
Console.WriteLine("Begin second task...");
GetMostCommonWords(words);
}, //close second Action
() =>
{
Console.WriteLine("Begin third task...");
GetCountForWord(words, "species");
} //close third Action
); //close parallel.invoke
Console.WriteLine("Returned from Parallel.Invoke");
#endregion
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
#region HelperMethods
private static void GetCountForWord(string[] words, string term)
{
var findWord = from word in words
where word.ToUpper().Contains(term.ToUpper())
select word;
Console.WriteLine(@"Task 3 -- The word ""{0}"" occurs {1} times.",
term, findWord.Count());
}
private static void GetMostCommonWords(string[] words)
{
var frequencyOrder = from word in words
where word.Length > 6
group word by word into g
orderby g.Count() descending
select g.Key;
var commonWords = frequencyOrder.Take(10);
StringBuilder sb = new StringBuilder();
sb.AppendLine("Task 2 -- The most common words are:");
foreach (var v in commonWords)
{
sb.AppendLine(" " + v);
}
Console.WriteLine(sb.ToString());
}
private static string GetLongestWord(string[] words)
{
var longestWord = (from w in words
orderby w.Length descending
select w).First();
Console.WriteLine("Task 1 -- The longest word is {0}", longestWord);
return longestWord;
}
// An http request performed synchronously for simplicity.
static string[] CreateWordArray(string uri)
{
Console.WriteLine("Retrieving from {0}", uri);
// Download a web page the easy way.
string s = new WebClient().DownloadString(uri);
// Separate string into an array of words, removing some common punctuation.
return s.Split(
new char[] { ' ', '\u000A', ',', '.', ';', ':', '-', '_', '/' },
StringSplitOptions.RemoveEmptyEntries);
}
#endregion
}
/* Output (May vary on each execution):
Retrieving from http://www.gutenberg.org/dirs/etext99/otoos610.txt
Response stream received.
Begin first task...
Begin second task...
Task 2 -- The most common words are:
species
selection
varieties
natural
animals
between
different
distinct
several
conditions
Begin third task...
Task 1 -- The longest word is characteristically
Task 3 -- The word "species" occurs 1927 times.
Returned from Parallel.Invoke
Press any key to exit
*/
}
@@IDENTITY返回的是当前会话中最后一次插入表单数据所在的标识值。
这个地方需要对当前会话
做个解释:连接一次数据库、打开一个查询分析器窗口执行SQL脚本、处理一次web对数据库的调用就是一次会话。
eg:
create table table1 (col1 int identity(1,1), col2 varchar(100))
create table table2 (col1 int identity(20,1), col2 varchar(100))
INSERT table1 VALUES ('book')
INSERT table2 VALUES ('kindle')
select @@IDENTITY -- 返回的是最后一张表标识值 20
我们再打开另外一个查询分析器执行:
INSERT table2 VALUES ('kindle')
select @@IDENTITY -- 返回的是标识值 21
然后在第一个查询分析器中执行:
select @@IDENTITY -- 发现返回的还是当前会话中的最后一次标识值 20
注意:当表单中有触发器或者其它存储过程执行时,注意要返回的标识值是否是我们所需。
SCOPE_IDENTITY()官方定义
:it returns the last identity value generated for any table, not just in the current session, but also for the current scope.
当前上下文
执行的最后插入的标识值。eg:
创建一个表单,创建这个表单的一个INSERT存储过程:
create table table3 (col1 int identity(1,1), col2 varchar(100))
GO
CREATE PROC InsertRow1 @value varchar(100)
AS
INSERT table3 VALUES (@value)
RETURN 0
GO
执行一个INSERT语句:
-- Insert row 1
INSERT table3 VALUES ('bork')
select @@IDENTITY [@@Identity], -- Returns 1
SCOPE_IDENTITY() [SCOPE_IDENTITY] -- Returns 1
FROM table3
然后,我们用存储过程执行,插入一条数据:
-- Run procedure to insert row 2
exec InsertRow1 'borkbork'
select @@IDENTITY [@@Identity], -- Returns 2
SCOPE_IDENTITY() [SCOPE_IDENTITY] -- 仍然返回的是 1!
FROM table3
好玩吧,^_^。
IDENT_CURRENT('表名')这个是最好理解的:返回无论何时何地(没有会话限制,没有上下文限制)插入的最后一条标识值。
可以在多个查询分析器中插入数据,然后在一个查询分析器中执行下面语句查看:
SELECT IDENT_CURRENT('table3') --每次INSERT 都会返回最后一次的标识值
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.