c yield improves code performance and readability

  • 2020-05-27 07:00:07
  • OfStack

I've seen N several times for the keyword "yield," and I didn't realize its power until recently. I'll show you some examples below of using "yield" to make your code more readable and perform better

To give you a quick overview of yield, I'll first show you an example that doesn't use this keyword. The code below is simple


IList<string> FindBobs(IEnumerable<string> names)
{
 var bobs = new List<string>();
 foreach(var currName in names)
 {
  if(currName == "Bob")
   bobs.Add(currName);
 }
 return bobs;
}

Notice I'm using IEnumerable here < string > As a parameter type and IList < string > As a return type, generally speaking, I prefer in the type of parameter input range is wide, the better, but more strict on the return type (translator note: the input multi-purpose base class or interface, came back with a subclass or implementation class), for input, if you need to use foreach to cycle, its use IEnumerable makes more sense. For the output, I use the interface to change the implementation. Here I want to save the caller the trouble of generating the list, so I choose list as the return type.

The problem is that my design is not linkable, and this design needs to generate a list as a return value. In practice, the list may not be large, but it doesn't have to be

Now let's look at doing this in an "yield" way, and then I'll explain how to use it and how it works.


IEnumerable<string> FindBobs(IEnumerable<string> names)
{
 foreach(var currName in names)
 {
  if(currName == "Bob")
   yield return currName;
 }
}

In this version, we change the return type to IEnumerable, and we use "yield return". Note that I no longer need to create a list, is this confusing? Don't worry, it will get easier and easier to understand how it works.

When the key phrase "yield return" is used,.net will generate a large string of pipe code for you, and you can pretend it's magic. When you start looping through the code being called (not list in this case), what happens on the implementation is that the function is called again and again, but each time it continues from the exit of the previous execution

The traditional method of execution
Call a function
The function executes and returns list
The call section USES the returned list
The execution method of Yield
Call a function
The caller requests item
The next item returns
Go back to step 2
While the implementation performed by yield might seem a bit complicated, we ended up only "popping" one item at a time, rather than creating the entire list and returning it.

Said to syntax, I personally think yield more concise, and for the purpose of the transfer function of better (translator note: code readability, that is), I use IEnumerable as the return type to notify the caller it can be foreach circulation and return data, and the caller can now decide whether it is willing to deposit will return to the list, even if it would come at the expense of performance.

In the simple example I provide, you may not find many benefits of using yield. However, you can save a lot of unnecessary work when the caller needs to cancel the loop through all the functions provided. When you use yield for method chaining, the amount of work you can save may multiply.

Ayende already has a great example :using yield for a slick pipes & filters implementation, he even says: version that is multi-threaded. It was very interesting to me.

My initial reservations about yield were that using this keyword might lead to potential performance problems, but in fact, I haven't found any information so far about the performance impact of yield, and the performance improvements I mentioned above are much larger than those of the compiler overhead.


Related articles: