降伏リターン説明!
yieldキーワードは、常に非常に誤解されたキーワードです
☞まず最初に、私たちには単純な
☞次の手順では、学生のリストを作成します
☞アプリケーションを実行し、どのように動作し、もう一度私たちは1000未満のIDを持つ学生に入力したい覚えてみましょう.
☞ブレークポイントを設定する🔴 アフターコール
もちろん..
➥我々が欲しいものは、100万の記録をつくって、リストに彼らを加えて、完全に100万の記録で水和されるそのリストを返すのを防ぐことになっています.
では、いくつかの修正を適用しましょう
☞我々は、現在
☞別のブレークポイントを設定しましょう
☞デバッガは、学生の中に行きます
☞その後、我々は内部です
☞F 10を使用してステップを続行します.あなたのキーワードをヒットします
☞実際に私たちは怠惰に学生のコレクションを繰り返している、我々は一度に1つの学生を要求しています.
☞両方の方法で我々は同じような結果を得ている
☞それらの違いは
☞実際には、基本的にイテレータを作成します.
我々
➥だから、全体のコレクションを繰り返す必要がないことによって、我々は実際にリスト内の100万人の学生を作成する必要はありませんでした、我々は実際にループし、最初の1000年を作成しました
使用するから
● 今、テストし、それが本当に違いを作っているかどうかを確認するアプリケーションのパフォーマンスを診断しましょう.
● このテストでは、ベンチマークネットNuGetパッケージを使用して、ここからダウンロードできますBenchmarkDotNet Nuget
● 我々は、単にベンチマーク統計を適用できるように我々のコードに簡単な編集を行います.
● 我々はクラスを作成し、それを呼び出しましょう
● 注意
● 今の経過時間の大きな違いに注意しても、メモリ使用量の巨大な違いに気付き、それは133.5 MB対220 KBです!
これは、単純な明確化のための
C#
, だから私は簡単な例ので、うまくいけば、それはあなたのアプリケーションのためのより良いパフォーマンスを得るのを助けるように理解できるように説明しようとします.➽コンソールアプリの作成
☞まず最初に、私たちには単純な
.Net Core 3.1
学生のリストを処理するコンソールアプリケーション.Student Class
には以下の構造体がある: public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
単純右のようですか?心配しないで、それはそのように保たれます😉☞次の手順では、学生のリストを作成します
main
コンソールアプリケーションのメソッド static void Main(string[] args)
{
CreateStudents();
}
☞だから私たちは単純な関数をCreateStudents
これは1つのパラメータ(作成する学生の数)を取り、この関数は、学生を作成し、もしstudent ID
が1000未満の場合、画面に入力されます.public static void CreateStudents()
{
var students = GetStudents(1000000);
foreach (var student in students)
{
if (student.Id < 1000)
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
else
break;
}
}
static IEnumerable<Student> GetStudents(int count)
{
var students = new List<Student>();
for (int i = 0; i < count; i++)
{
students.Add(new Student() { Id = i, Name = $"Student Number {i}" });
}
return students;
}
☞ GetStudents
関数は、新しい学生リストを作成し、新しい学生とそれを記入し、それを返します.☞アプリケーションを実行し、どのように動作し、もう一度私たちは1000未満のIDを持つ学生に入力したい覚えてみましょう.
☞ブレークポイントを設定する🔴 アフターコール
GetStudents
関数は、100万人の学生が作成されることに注意してくださいforeach
ループは最初の1000のみを印刷するために入力されますので、我々は本当に1000😖 ? もちろん..
➥我々が欲しいものは、100万の記録をつくって、リストに彼らを加えて、完全に100万の記録で水和されるそのリストを返すのを防ぐことになっています.
➽適用収益リターン
では、いくつかの修正を適用しましょう
CreateStudents
機能.static IEnumerable<Student> GetStudents(int count)
{
for (int i = 0; i < count; i++)
{
yield return new Student() { Id = i, Name = $"Student Number {i}" };
}
}
☞のは、同じブレークポイントを設定すると、アプリケーションを実行して何が起こるかを参照してください.☞我々は、現在
foreach
ループゼロ学生と作成!☞別のブレークポイントを設定しましょう
yield return
ラインインサイドGetStudents
関数は、実際に何が起こっているかを見て、Visual StudioのステップF 10を押してデバッグプロセスを継続します.☞デバッガは、学生の中に行きます
foreach
その後、キーワードの上にループしてreturn yield
ラインインGetStudents
関数をステップインしないforeach
インCreateStudents
機能.☞その後、我々は内部です
foreach
次に、if文を入力し、最初の学生のデータをコンソールに印刷します.☞F 10を使用してステップを続行します.あなたのキーワードをヒットします
**in**
にforeach
それから、return yield
再び.➽それで、我々は本当にここで何をしていますか?
☞実際に私たちは怠惰に学生のコレクションを繰り返している、我々は一度に1つの学生を要求しています.
☞両方の方法で我々は同じような結果を得ている
☞それらの違いは
yield return
パフォーマンスとメモリ使用量の巨大な改善を行います.☞実際には、基本的にイテレータを作成します.
我々
foreach
ループは、このような声明のための構文的な砂糖ですvar studentesEnumerator = students.GetEnumerator();
while (studentesEnumerator.MoveNext())
{
var student = studentesEnumerator.Current;
}
これは大まかにコンパイルするものの種類です.➥だから、全体のコレクションを繰り返す必要がないことによって、我々は実際にリスト内の100万人の学生を作成する必要はありませんでした、我々は実際にループし、最初の1000年を作成しました
使用するから
yield
私たちがこのループに入ったとき、生徒は一度に一つずつ創造します.➽ベンチマークDOTNETを使用して差分をテストします。
● 今、テストし、それが本当に違いを作っているかどうかを確認するアプリケーションのパフォーマンスを診断しましょう.
● このテストでは、ベンチマークネットNuGetパッケージを使用して、ここからダウンロードできますBenchmarkDotNet Nuget
● 我々は、単にベンチマーク統計を適用できるように我々のコードに簡単な編集を行います.
● 我々はクラスを作成し、それを呼び出しましょう
YieldBenchmarks
, このクラスには、古いバージョンの関数とyield returnを使用した新しいバージョンが含まれます.このクラスは、[ MemoryManager ]属性とCreateStudent
関数は[ベンチマーク]属性で修飾され、コードは次のようになります [MemoryDiagnoser]
public class YieldBenchmarks
{
[Benchmark]
public void CreateStudents()
{
var students = GetStudents(1000000);
foreach (var student in students)
{
if (student.Id < 1000)
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
else
break;
}
}
static IEnumerable<Student> GetStudents(int count)
{
var students = new List<Student>();
for (int i = 0; i < count; i++)
{
students.Add(new Student() { Id = i, Name = $"Student Number {i}" });
}
return students;
}
[Benchmark]
public void CreateStudentsYield()
{
var students = GetStudentsYield(1000000);
foreach (var student in students)
{
if (student.Id < 1000)
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
else
break;
}
}
static IEnumerable<Student> GetStudentsYield(int count)
{
for (int i = 0; i < count; i++)
{
yield return new Student() { Id = i, Name = $"Student Number {i}" };
}
}
}
とmain
関数は以下のようになります: static void Main(string[] args)
{
var result = BenchmarkRunner.Run<YieldBenchmarks>();
}
● では、リリースモードでアプリケーションを実行しましょう.● 注意
BenchmarkRunner
各関数を複数回実行して、その診断を実行できるようになります.● 今の経過時間の大きな違いに注意しても、メモリ使用量の巨大な違いに気付き、それは133.5 MB対220 KBです!
これは、単純な明確化のための
yield
キーワード、次に、async yieldで行きます.待ちます:)Reference
この問題について(降伏リターン説明!), 我々は、より多くの情報をここで見つけました https://dev.to/ahmedadel/yield-return-explained-262dテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol