C#用Parallel.Invoke方法盡可能并行執(zhí)行提供的每個線程
盡可能并行執(zhí)行提供的每個操作。使用Parallel.Invoke 方法。
最簡單,最簡潔的將串行的代碼并行化。
一、重載
| Invoke(Action[]) | 盡可能并行執(zhí)行提供的每個操作。 |
| Invoke(ParallelOptions, Action[]) | 執(zhí)行所提供的每個操作,而且盡可能并行運行,除非用戶取消了操作。 |
二、Invoke(Action[])
盡可能并行執(zhí)行提供的每個操作。
1.定義
public static void Invoke (params Action[] actions); 參數(shù) actions Action[] 要執(zhí)行的 Action 數(shù)組。 例外 ArgumentNullException actions 參數(shù)為 null。 AggregateException 當 actions 數(shù)組中的任何操作引發(fā)異常時引發(fā)的異常。 ArgumentException actions數(shù)組包含 null 個元素。
2.示例
Invoke方法經(jīng)常與其他方法、匿名委托和 lambda 表達式配合使用,實現(xiàn)并行方法的線程同步。
// Parallel.Invoke()方法
// 將 Invoke 方法與其他方法、匿名委托和 lambda 表達式結(jié)合使用。
namespace ConsoleApp15
{
class ParallelInvokeDemo
{
/// <summary>
/// 執(zhí)行每個任務的線程可能不同。
/// 不同的執(zhí)行中線程分配可能不同。
/// 任務可能按任何順序執(zhí)行。
/// </summary>
static void Main()
{
try
{
Parallel.Invoke(
BasicAction, // Param #0 - static method
() => // Param #1 - lambda expression
{
Console.WriteLine("Method=beta, Thread={0}", Environment.CurrentManagedThreadId);
},
delegate () // Param #2 - in-line delegate
{
Console.WriteLine("Method=gamma, Thread={0}", Environment.CurrentManagedThreadId);
}
);
}
// 一般不會出現(xiàn)異常,但如萬一拋出異常,
// 它將被包裝在 AggregateException 中并傳播到主線程。
catch (AggregateException e)
{
Console.WriteLine("An action has thrown an exception. THIS WAS UNEXPECTED.\n{0}", e.InnerException!.ToString());
}
}
static void BasicAction()
{
Console.WriteLine("Method=alpha, Thread={0}", Environment.CurrentManagedThreadId);
}
}
}
// 運行結(jié)果:
/*
Method=beta, Thread=4
Method=alpha, Thread=1
Method=gamma, Thread=10
*/三、Invoke(ParallelOptions, Action[])
執(zhí)行所提供的每個操作,而且盡可能并行運行,除非用戶取消了操作。
1.定義
public static void Invoke (System.Threading.Tasks.ParallelOptions parallelOptions, params Action[] actions); 參數(shù) parallelOptions ParallelOptions 一個對象,用于配置此操作的行為。 actions Action[] 要執(zhí)行的操作數(shù)組。 例外 OperationCanceledException CancellationToken 處于 parallelOptions 設(shè)置。 ArgumentNullException actions 參數(shù)為 null。 或 - parallelOptions 參數(shù)為 null。 AggregateException 當 actions 數(shù)組中的任何操作引發(fā)異常時引發(fā)的異常。 ArgumentException actions數(shù)組包含 null 個元素。 ObjectDisposedException 在 parallelOptions 中與 CancellationTokenSource 關(guān)聯(lián)的 CancellationToken 已被釋放。 注解 此方法可用于執(zhí)行一組可能并行的操作。 使用結(jié)構(gòu)傳入 ParallelOptions 的取消令牌使調(diào)用方能夠取消整個操作。
2. 常用的使用方法
Parallel.Invoke(
() => { },
() => { },
() => { }
);(1)示例1
- 一個任務是可以分解成多個任務,采用分而治之的思想;
- 盡可能的避免子任務之間的依賴性,因為子任務是并行執(zhí)行,所以就沒有誰一定在前,誰一定在后的規(guī)定了;
- 主線程必須等Invoke中的所有方法執(zhí)行完成后返回才繼續(xù)向下執(zhí)行。暗示以后設(shè)計并行的時候,要考慮每個Task任務盡可能差不多,如果相差很大,比如一個時間非常長,其他都比較短,這樣一個線程可能會影響整個任務的性能。這點非常重要;
- 沒有固定的順序,每個Task可能是不同的線程去執(zhí)行,也可能是相同的;
namespace ConsoleApp16
{
internal class Program
{
private static void Main(string[] args)
{
ArgumentNullException.ThrowIfNull(args);
ParallelMothed();
static void ParallelMothed()
{
Parallel.Invoke(Run1, Run2); //這里的Run1 Run2 都是方法。
}
}
static void Run1()
{
Console.WriteLine("我是任務一,我跑了3s");
Thread.Sleep(3000);
}
static void Run2()
{
Console.WriteLine("我是任務二,我跑了5s");
Thread.Sleep(5000);
}
}
}
//運行結(jié)果:
/*
我是任務二,我跑了5s
我是任務一,我跑了3s
*/(2)示例2
如果調(diào)用的方法是有參數(shù)的,如何處理?同理,直接帶上參數(shù)就可以,
Parallel.Invoke(() => Task1("task1"), () => Task2("task2"), () => Task3("task3"));// Invoke帶參數(shù) 調(diào)用
using System.Diagnostics;
namespace ConsoleApp17
{
class ParallelInvoke
{
public static void Main(string[] args)
{
ArgumentNullException.ThrowIfNull(args);
Stopwatch stopWatch = new();
Console.WriteLine("主線程:{0}線程ID : {1};開始", "Main", Environment.CurrentManagedThreadId);
stopWatch.Start();
Parallel.Invoke(
() => Task1("task1"),
() => Task2("task2"),
() => Task3("task3")
);
stopWatch.Stop();
Console.WriteLine("主線程:{0}線程ID : {1};結(jié)束,共用時{2}ms", "Main", Environment.CurrentManagedThreadId, stopWatch.ElapsedMilliseconds);
Console.ReadKey();
}
private static void Task1(string data)
{
Thread.Sleep(5000);
Console.WriteLine("任務名:{0}線程ID : {1}", data, Environment.CurrentManagedThreadId);
}
private static void Task2(string data)
{
Console.WriteLine("任務名:{0}線程ID : {1}", data, Environment.CurrentManagedThreadId);
}
private static void Task3(string data)
{
Console.WriteLine("任務名:{0}線程ID : {1}", data, Environment.CurrentManagedThreadId);
}
}
}
//運行結(jié)果:
/*
主線程:Main線程ID : 1;開始
任務名:task2線程ID : 4
任務名:task3線程ID : 7
任務名:task1線程ID : 1
主線程:Main線程ID : 1;結(jié)束,共用時5020ms
*/(3)Stopwatch類
提供一組方法和屬性,可用于準確地測量運行時間。
其中,Stopwatch.Start 方法和Stopwatch.Stop 方法
public class Stopwatch
使用 Stopwatch 類來確定應用程序的執(zhí)行時間。
// 使用 Stopwatch 類來確定應用程序的執(zhí)行時間
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
ArgumentNullException.ThrowIfNull(args);
Stopwatch stopWatch = new();
stopWatch.Start();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
// Format and display the TimeSpan value.
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
}
}
//運行結(jié)果:
/*
RunTime 00:00:10.01
*/
// 使用 Stopwatch 類來計算性能數(shù)據(jù)。
using System.Diagnostics;
namespace StopWatchSample
{
class OperationsTimer
{
public static void Main(string[] args)
{
ArgumentNullException.ThrowIfNull(args);
DisplayTimerProperties();
Console.WriteLine();
Console.WriteLine("Press the Enter key to begin:");
Console.ReadLine();
Console.WriteLine();
TimeOperations();
}
public static void DisplayTimerProperties()
{
// Display the timer frequency and resolution.
if (Stopwatch.IsHighResolution)
{
Console.WriteLine("Operations timed using the system's high-resolution performance counter.");
}
else
{
Console.WriteLine("Operations timed using the DateTime class.");
}
long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = {0}",frequency);
long nanosecPerTick = (1000L * 1000L * 1000L) / frequency;
Console.WriteLine(" Timer is accurate within {0} nanoseconds",nanosecPerTick);
}
private static void TimeOperations()
{
long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
const long numIterations = 10000;
// Define the operation title names.
string[] operationNames = {"Operation: Int32.Parse(\"0\")",
"Operation: Int32.TryParse(\"0\")",
"Operation: Int32.Parse(\"a\")",
"Operation: Int32.TryParse(\"a\")"};
// Time four different implementations for parsing
// an integer from a string.
for (int operation = 0; operation <= 3; operation++)
{
// Define variables for operation statistics.
long numTicks = 0;
long numRollovers = 0;
long maxTicks = 0;
long minTicks = long.MaxValue;
int indexFastest = -1;
int indexSlowest = -1;
Stopwatch time10kOperations = Stopwatch.StartNew();
// Run the current operation 10001 times.
// The first execution time will be tossed
// out, since it can skew the average time.
for (int i = 0; i <= numIterations; i++)
{
long ticksThisTime = 0;
int inputNum;
Stopwatch timePerParse;
switch (operation)
{
case 0:
// Parse a valid integer using
// a try-catch statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch.StartNew();
try
{
inputNum = int.Parse("0");
}
catch (FormatException)
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse.Stop();
ticksThisTime = timePerParse.ElapsedTicks;
break;
case 1:
// Parse a valid integer using
// the TryParse statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch.StartNew();
if (!int.TryParse("0", out inputNum))
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse.Stop();
ticksThisTime = timePerParse.ElapsedTicks;
break;
case 2:
// Parse an invalid value using
// a try-catch statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch.StartNew();
try
{
inputNum = int.Parse("a");
}
catch (FormatException)
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse.Stop();
ticksThisTime = timePerParse.ElapsedTicks;
break;
case 3:
// Parse an invalid value using
// the TryParse statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch.StartNew();
if (!int.TryParse("a", out inputNum))
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse.Stop();
ticksThisTime = timePerParse.ElapsedTicks;
break;
default:
break;
}
// Skip over the time for the first operation,
// just in case it caused a one-time
// performance hit.
if (i == 0)
{
time10kOperations.Reset();
time10kOperations.Start();
}
else
{
// Update operation statistics
// for iterations 1-10000.
if (maxTicks < ticksThisTime)
{
indexSlowest = i;
maxTicks = ticksThisTime;
}
if (minTicks > ticksThisTime)
{
indexFastest = i;
minTicks = ticksThisTime;
}
numTicks += ticksThisTime;
if (numTicks < ticksThisTime)
{
// Keep track of rollovers.
numRollovers++;
}
}
}
// Display the statistics for 10000 iterations.
time10kOperations.Stop();
long milliSec = time10kOperations.ElapsedMilliseconds;
Console.WriteLine();
Console.WriteLine("{0} Summary:", operationNames[operation]);
Console.WriteLine(" Slowest time: #{0}/{1} = {2} ticks",
indexSlowest, numIterations, maxTicks);
Console.WriteLine(" Fastest time: #{0}/{1} = {2} ticks",
indexFastest, numIterations, minTicks);
Console.WriteLine(" Average time: {0} ticks = {1} nanoseconds",
numTicks / numIterations,
(numTicks * nanosecPerTick) / numIterations);
Console.WriteLine(" Total time looping through {0} operations: {1} milliseconds",
numIterations, milliSec);
}
}
}
}
//運行結(jié)果:
/*
Operations timed using the system's high-resolution performance counter.
Timer frequency in ticks per second = 10000000
Timer is accurate within 100 nanoseconds
*/1.Stopwatch.Start 方法
開始或繼續(xù)測量某個時間間隔的運行時間。
前例中有示例。
public void Start ();
2.Stopwatch.Stop 方法
停止測量某個時間間隔的運行時間。
public void Stop ();
前例中有示例。
到此這篇關(guān)于C#用Parallel.Invoke方法盡可能并行執(zhí)行提供的每個線程的文章就介紹到這了,更多相關(guān)C# Parallel.Invoke并行執(zhí)行提供線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#?將數(shù)據(jù)庫SqlServer數(shù)據(jù)綁定到類中的過程詳解
本文講述的是讀取數(shù)據(jù)庫中數(shù)據(jù)的常用做法,即將數(shù)據(jù)庫中的數(shù)據(jù)綁定到創(chuàng)建的類中,再將類綁定到DataGridView的數(shù)據(jù)源中的做法,對C#將SqlServer數(shù)據(jù)綁定到類中感興趣的朋友一起看看吧2022-06-06
C# JavaScriptSerializer序列化時的時間處理詳解
這篇文章主要為大家詳細介紹了C# JavaScriptSerializer序列化時的時間處理詳解,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08

