目录
介绍
延迟计算
公平调度
公平线程池
- 下载源代码 - 9.3 KB
本文简要介绍了C中的延迟计算和公平调度的概念。
延迟计算延迟计算(懒惰计算)是一种计算策略,它将表达式的计算延迟到需要它的值时候,并且还避免重复计算。共享可以通过指数因子比其他非严格计算策略(例如按名称调用)减少某些函数的运行时间。
下面列出了延迟计算的好处:
- 通过避免不必要的计算以及计算复合表达式的错误条件来提高性能
- 构建潜在无限数据结构的能力
- 将控制流(结构)定义为抽象而不是原始的能力
.NET Framework提供了Lazy 以管理延迟计算。为了初始化一个延迟表达式,可以通过lambda来完成:
var lazyNumber = new Lazy(() => 42);
Console.WriteLine(lazyNumber.Value); // -> 42
在下面的示例中,我们创建了两个惰性表达式,我们将尝试添加它们:
var x = new Lazy(() => 42); // -> Value is not created
var y = new Lazy(() => 24); // -> Value is not created
Console.WriteLine(x + y); // Error : operator '+' cannot be applied
Console.WriteLine(x.Value + y.Value); // -> 66
在下面的示例中,我们创建了一个实现边缘效果的延迟表达式,我们将尝试将其冻结。
var p = new Lazy(() => { Console.WriteLine("Boo"); return null; });
// Cannot create Lazy in C#, so return null
让我们尝试创建自己的Lazy:
public class MyLazy
{
private readonly Func _f;
private bool _hasValue;
private T _value;
public MyLazy(Func f)
{
_f = f;
}
//
// Use objects of type MyLazy as objects of type T
// through implicit keyword
//
public static implicit operator T(MyLazy lazy)
{
if (!lazy._hasValue)
{
lazy._value = lazy._f();
lazy._hasValue = true;
}
return lazy._value;
}
}
MyLazy 是一个包含以下字段的泛型类:
- _f:延迟计算的函数,返回T类型的值
- _value:T类型的值 (冻结值)
- _hasValue:一个布尔值,指示是否已计算该值
为了使用MyLazy类型的对象作为T类型的对象,使用implicit关键字。计算在类型转换时完成。
下面是一个MyLazy示例用法。
var myLazyRandom = new MyLazy(GetRandomNumber);
double myRandom = myLazyRandom;
Console.WriteLine("Random with MyLazy: {0}", myRandom);
其中GetRandomNumber返回随机double,如下:
static double GetRandomNumber(){
Random r = new Random();
return r.NextDouble();
}
公平调度
公平调度是一种调度方法,其中所有作业随时间获得相等的资源份额。CPU使用率在系统中平均分配。
假设我们想要创建以下公平调度系统:管理处理器的中央系统分配给一组线程,以便每个线程都有一段时间。
线程将被建模为由处理器测试的代码并被切割成小块。这些部件中的每一件都将花费时间。处理器具有多个可同时处理的线程,可调度线程并让它们分段运行。为了选择要执行的线程,处理器将选择成本最低的线程。
线程将有一个叫做ThreadId的整数,表示线程标识符和一个计算已完成工作量的整数Workload。线程的工件将通过IEnumerable类型的Worker属性表示。
因此:
- Worker.Current值表示最后一件完成的成本
- Worker.MoveNext()操作使线程完成一项工作
为简单起见,该线程将有一个方法Work(),其让线程完成一项工作并将其工作量添加到Workload中。
在下面的示例代码中,我们创建了一个包含10个线程的列表。
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
public class Thread
{
public int Workload { get; set; }
public int ThreadId { get; private set; }
private IEnumerator Worker; // an enumerator for these parts
public Thread()
{
Workload = 0;
ThreadId = rng.Next() % 100 + 100;
Worker = CreateWorker(this).GetEnumerator();
}
public int Work()
{
int load = Worker.Current;
Workload += load;
Worker.MoveNext();
return load;
}
// Work processor (metaphorized)
static Random rng = new Random();
static IEnumerable CreateWorker(Thread p)
{
while (true)
{
int load = rng.Next() % 9 + 1;
Console.WriteLine("{0} : working for {1} hours (total load : {2})",
p.ThreadId, load, p.Workload);
yield return load;
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Yield!");
var ListOfThreads = new List();
for (int i = 0; i < 10; i++)
{
var processor = new Thread();
ListOfThreads.Add(processor);
}
Thread p;
for (int i = 0; i < 500; i++)
{
p = ListOfThreads.Aggregate((curp, next) => {
if (next.Workload < curp.Workload)
return next;
else return curp;
});
p.Work();
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
在方法Main、first和formost中,创建了10个线程的列表。然后,线程的调度是在知道应该工作的线程是具有最小工作负载的线程的情况下完成的。
公平线程池可以创建一个线程池,允许以公平的方式安排作业。随着时间的推移,所有工作都将获得相同的资源份额。因此,CPU使用率将在系统之间平均分配。
作业将在与标记关联的池中排队。要选择要运行的作业,池中的线程会循环遍历标记。因此,将保证与标签相关联的作业永远不会被与另一个标签相关联的一堆作业阻止。从队列中挑选作业时,池将在标记之间交替。
原文地址:https://www.codeproject.com/Articles/5162791/Introducting-Lazy-Evaluation-And-Fair-Scheduling-I