Created
March 29, 2019 01:19
-
-
Save francipvb/1b02db167e29a02bfa1343e60b4e6d8b to your computer and use it in GitHub Desktop.
Calculating prime numbers with enumerable functions and tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace Prime | |
{ | |
class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
// Without this, we cann't cancel the operation gracefully | |
var token = new CancellationTokenSource(); | |
// Here we use the cancellation token to cancel an operation | |
Console.CancelKeyPress += (sender, e) => | |
{ | |
e.Cancel = true; | |
token.Cancel(); | |
}; | |
// Start time | |
var t1 = DateTime.Now; | |
// This is not a list of prime numbers, but an enumerable | |
// This functions doesn't runs until we attempt to get the enumeration results | |
var numList = GetPrimeNumbers(8, token.Token); | |
// This runs the iterator until the end | |
var numCount = numList.Count(); | |
// End time | |
var t2 = DateTime.Now; | |
// Time difference | |
var tDif = t2 - t1; | |
// Print our results (not the number list, but the number count) | |
Console.WriteLine("Got {0} prime numbers in {1:m' minutes, 's' seconds'}.", numCount, tDif); | |
Console.ReadKey(); | |
} | |
private static IEnumerable<ulong> GetPrimeNumbers(int tasks, CancellationToken token) | |
{ | |
var tList = new List<Task<(ulong, bool)>>(); | |
for (ulong i = 1; i < ulong.MaxValue; i++) | |
{ | |
if (tList.Count < tasks) | |
{ | |
// We need to do this concurrently, so we must add these tasks to a list | |
tList.Add(Task.Run( | |
() => (i, IsPrime(i, token)))); | |
} | |
if (token.IsCancellationRequested) | |
{ | |
// If we pressed CTRL+C, it is true | |
// We can break the for loop here and check for completed tasks. | |
break; | |
} | |
if (tList.Count == tasks) | |
{ | |
var tarea = Task.WhenAny(tList); | |
// We must wait until any of these tasks is completed | |
tarea.Wait(); | |
// Now, we must make a place to another task | |
tList.Remove(tarea.Result); | |
if (!tarea.Result.IsCompletedSuccessfully) | |
{ | |
throw tarea.Result.Exception; | |
} | |
if (tarea.Result.Result.Item2) | |
{ | |
// Here are the magic of enumerator functions | |
yield return tarea.Result.Result.Item1; | |
} | |
} | |
} | |
// Probably there are incomplete tasks | |
foreach (var t in Task.WhenAll(tList) | |
.GetAwaiter() | |
.GetResult()) | |
{ | |
if (t.Item2) | |
{ | |
// Returning the rest of the results | |
yield return t.Item1; | |
} | |
} | |
} | |
private static bool IsPrime(ulong num, CancellationToken token = default(CancellationToken)) | |
{ | |
if (num == 0) | |
{ | |
return false; | |
} | |
if (num <= 3) | |
{ | |
return true; | |
} | |
for (ulong i = 2; i <= num / 2; i++) | |
{ | |
if (num % i == 0) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment