您的位置:首页 > 编程语言 > C#

C#之任务,线程和同步

2016-02-06 15:05 375 查看

1 概述

  对于所有需要等待 的操作,例 如 ,因 为文件 、 数据库或网络访 问都需要一定 的时间,此 时就可以启 动一个新线程,同时完成其他任务,即使是处理密集型的任务,线程也是有帮助的。

2 Parallel类

  2.1 用Parallel.For()方法循环

  Parallel.For()方法类似于C#的For循环,多次执行一个任务,它可以并行运行迭代。迭代的顺序没有定义。

ParallelLoopResult result = Parallel.For(0, 10, i =>
{
Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
});
Console.WriteLine(result.IsCompleted);


  在For()方法中,前两个参数定义了循环的开头和结束。从输出可以看出,顺序是不能保证的。也可以提前中断Parallel.For()方法。

ParallelLoopResult result2 = Parallel.For(10, 40, (int i,ParallelLoopState pls) =>
{
Console.WriteLine("i: {0},task:{1}", i, Task.CurrentId);
Thread.Sleep(10);
if (i > 15)
pls.Break();
});
Console.WriteLine(result2.IsCompleted);
Console.WriteLine( "lowest break iteration:{0}",result2.LowestBreakIteration);


  2.2 用Parallel.ForEach()方法循环

  paraller.ForEach()方法遍历实现了IEnumerable的集合,其方式类似于Foreach语句,但以异步方式遍历,这里也没有确定的遍历顺序。

string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" };
//  Parallel.ForEach(data, s => { Console.WriteLine(s); });
Parallel.ForEach(data, (s, pls) => { if (s == "one") { Console.WriteLine("break......"); pls.Break(); } Console.WriteLine(s); Thread.Sleep(100); });


  2.3 通过Paraller.Invoke()调用多个方法

Parallel.Invoke(Foo ,Bar);

static void Foo() { Console.WriteLine("foo"); }
static void Bar() { Console.WriteLine("bar"); }


3 任务

  .NET 4 包含新的名称空间System.Threading.Task,它它 包含的类抽象出了线程功能,在后台使用ThreadPool。 任务表示应完成的某个单元的工作。 这个单元的工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调线程。

  3.1启动任务

  要启动任务,可 以使用 TaskFactory类 或 Task类 的构造函数和 start()方 法。 Task类 的构造函数在创建任务上提供的灵活性较大.

//using TaskFactory
Task t1 = new TaskFactory().StartNew(TaskMethod);
//using the task factory via task
Task t2 = Task.Factory.StartNew(TaskMethod);
//using task constructor
Task t3 = new Task(TaskMethod);
t3.Start();


使用 Task类 的构造函数和 TaskFactory类 的 stamw()方法时,都可以传递TaskCreationOptions枚举中的值。 设置LongRunning选项,可 以通知任务调度器,该 任务需要较长时间执行,这样调度器更可能使用 新线。 如果该任务应关联到父任务上,而父任务取消了,则 该任务也应取消,此 时应设置 AuachToParent选 项。PerferFairness 值表示,调度器应提取出已在等待的第一个任务。 如果任务使用 子任务创建了其他工作,子
任务就优先于其他任务。 它们不会排在线程池队列中的最后。 如果这些任务应 以公平的方式与所有其他任务一起处理,就设置该选项为PreferFairness

Task t5 = t4.ContinueWith(DoSecond,TaskContinuationOptions.PreferFairness);


  3.2连续的任务

  通过任务,可 以指定在任务完成后,应 开始运行另一个特定任务.

static void DoOnFirst()
{
Console.WriteLine("doing some task {0}",Task.CurrentId);
Thread.Sleep(3000);
}
static void DoSecond(Task t)
{
Console.WriteLine("task {0} finished",t.Id);
Console.WriteLine("this task id {0}",Task.CurrentId);
Console.WriteLine("do some cleanup");
Thread.Sleep(3000);
}

Task t1 = new Task(DoOnFirst);
Task t2 = t1.ContinueWith(DoSecond);
Task t3 = t2.ContinueWith(DoSecond);
Task t4 = t3.ContinueWith(DoSecond);
Task t5 = t4.ContinueWith(DoSecond,TaskContinuationOptions.PreferFairness);
t1.Start();


无论前一个任务是如何结束的,前 面 的连续任务总是在前一个任务结束时启 动 。 使用TaskContinuationOptions 枚举中的值,可 以指定,连续任务只有在起始任务成功(或失败)结束时启动。

  3.3任务层次的结构

static void ParentAndChild()
{
var parent = new Task(ParentTask);
parent.Start();
Thread.Sleep(2000);
Console.WriteLine(parent.Status);
Thread.Sleep(4000);
Console.WriteLine(parent.Status);
Console.WriteLine();
}
private static void ParentTask()
{
Console.WriteLine("task id {0}",Task.CurrentId);
var child = new Task(ChildTask);
child.Start();
Thread.Sleep(1000);
Console.WriteLine("parent started child");
}

private static void ChildTask()
{
Console.WriteLine("child");
Thread.Sleep(5000);
Console.WriteLine("child finished");
}


如果父任务在子任务之前结束 ,父 任务的状态就显示为WaitingForChildrenToComplete.只要子任务也结束 时,父任务的状态就变成RanToCompletion。 ·

4 取消架构

  4.1Parallel.For()方法的取消

var cts = new CancellationTokenSource();
cts.Token.Register(() => Console.WriteLine("token canceled"));
new Task(() => { Thread.Sleep(500); cts.Cancel(false); }).Start();
try
{
ParallelLoopResult result = Parallel.For(0, 100, new ParallelOptions() { CancellationToken = cts.Token, }, x =>
{
Console.WriteLine("loop {0} started", x);
int sun = 0;
for (int i = 0; i < 100; i++)
{
Thread.Sleep(2);
sun += i;
}
Console.WriteLine("loop {0} finished",x);
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}


  4.2任务的取消

  同样的取消模式也可用于任务。

5 线程池

  如果有不同的小任务要完成,就可以事先创建许多线程 ,· 在应完成这些任务时发出请求。 这个线程数最好在需要更多的线程时增加,在 需要释放资源时减少。不需要自己创建这样一个列表。 该列表由 ThreadPool类 托管。 这个类会在需要时增减池中线程的线程数,直 到最大的线程数。 池中的最大线程数是可配置的。如果有更多的作业要处理,线 程池中线程的个数也到了极限,最 新的作业就要排队,且 必须等待线程完成其任务。

static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
bool createNew;

Mutex m = new Mutex(false, "test", out createNew);
if (!createNew)
{
MessageBox.Show("程序已启动");
Application.Exit();
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: