Outils pour utilisateurs

Outils du site


developpement:dotnet:csharp:introduction

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
developpement:dotnet:csharp:introduction [2023/10/04 17:23] – [Task Parallel Library (TPL)] sgariepydeveloppement:dotnet:csharp:introduction [2023/10/06 05:06] (Version actuelle) – [Reactive] sgariepy
Ligne 1271: Ligne 1271:
  
 Le cas en parallèle prend plus de temps dû au overhead.  L'instruction n'étant pas assez complexe pour justifier la parallèlisation. Le cas en parallèle prend plus de temps dû au overhead.  L'instruction n'étant pas assez complexe pour justifier la parallèlisation.
 +
 +
 +<code csharp>
 +// Générer des images: https://picsum.photos/3840/2160
 +
 +void Main()
 +{
 +    var path = Directory.GetCurrentDirectory();
 +    var files = Directory.GetFiles(path + @"\pictures", "*.jpg");
 +    
 +    var normalAlteredPath = path + @"\normalAlteredPath";
 +    var parallelAlteredPath = path + @"\parallelAlteredPath";
 +    Directory.CreateDirectory(normalAlteredPath);
 +    Directory.CreateDirectory(parallelAlteredPath);
 +    
 +    ParallelExecutionMode(files, normalAlteredPath);
 +    NormalExecutionMode(files, parallelAlteredPath);
 +}
 +
 +void NormalExecutionMode(string[] files, string alteredPath)
 +{
 +    Stopwatch stopwatch = Stopwatch.StartNew();
 +    foreach (var currentFile in files)
 +    {
 +        var file = Path.GetFileName(currentFile);
 +        using (var fileBitmap = new Bitmap(currentFile))
 +        {
 +            fileBitmap.RotateFlip(RotateFlipType.Rotate270FlipX);
 +            fileBitmap.Save(Path.Combine(alteredPath, file));
 +            Console.WriteLine("Thread {0}", Thread.CurrentThread.ManagedThreadId);
 +        }
 +    }
 +    Console.WriteLine("Normal execution time: {0}", stopwatch.ElapsedMilliseconds);
 +    stopwatch.Stop();
 +}
 +
 +void ParallelExecutionMode(string[] files, string alteredPath)
 +{
 +    Stopwatch stopwatch = Stopwatch.StartNew();
 +
 +    Parallel.ForEach(files, currentFile => {
 +        var file = Path.GetFileName(currentFile);
 +        using (var fileBitmap = new Bitmap(currentFile))
 +        {
 +            fileBitmap.RotateFlip(RotateFlipType.Rotate270FlipX);
 +            fileBitmap.Save(Path.Combine(alteredPath, file));
 +            Console.WriteLine("Thread {0}", Thread.CurrentThread.ManagedThreadId);
 +        }
 +    });
 +
 +    Console.WriteLine("Parallel execution time: {0}", stopwatch.ElapsedMilliseconds);
 +    stopwatch.Stop();
 +}
 +</code>
 +
 +
 +
 +<code csharp>
 +void Main()
 +{
 +    var list = Enumerable.Range(0, 100000000).ToArray();
 +    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
 +    
 +    ParallelOptions parallelOptions = new ParallelOptions();
 +    parallelOptions.CancellationToken = cancellationTokenSource.Token;
 +    parallelOptions.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
 +    
 +    Console.WriteLine("Press 'x' to cancel");
 +    
 +    Task.Factory.StartNew(() =>
 +    {
 +        if (Console.ReadLine() == "x")
 +        {
 +            cancellationTokenSource.Cancel();
 +        }
 +    
 +        long total = 0;
 +        
 +        try
 +        {
 +            Parallel.For<long>(0, list.Length, parallelOptions, () => 0, (count, parallelLoopState, subtotal) =>
 +            {
 +                Thread.Sleep(200);
 +                parallelOptions.CancellationToken.ThrowIfCancellationRequested();
 +                subtotal += list[count];
 +                return subtotal;
 +            },
 +            (x) =>
 +            {
 +                Interlocked.Add(ref total, x);
 +            });
 +        }
 +        catch (OperationCanceledException ex)
 +        {
 +            Console.WriteLine("Cancelled " + ex.Message);
 +        }
 +        finally
 +        {
 +            cancellationTokenSource.Dispose();
 +        }
 +        Console.WriteLine("The final sum is {0}", total);
 +    });
 +    
 +}
 +</code>
 +
 +===== Continuation with state =====
 +
 +<code csharp>
 +void Main()
 +{
 +    Task<DateTime> task = Task.Run(() => DoSomething());
 +    List<Task<DateTime>> continuationTasks = new List<Task<DateTime>>();
 +    
 +    for (int i = 0; i < 3; i++)
 +    {
 +        task = task.ContinueWith((x, y) => DoSomething(), new Person { Id = i });
 +        continuationTasks.Add(task);
 +    }
 +    
 +    task.Wait();
 +    
 +    foreach (var continuation in continuationTasks)
 +    {
 +        Person person = continuation.AsyncState as Person;
 +        Console.WriteLine("Task finished at " + continuation.Result + ". Person id is {0}", person.Id);
 +    }
 +}
 +
 +static DateTime DoSomething()
 +{
 +    return DateTime.Now;
 +}
 +
 +internal class Person
 +{
 +    public int Id { get; set; }
 +}
 +</code>
 +
 +===== TaskCompletionSource =====
 +
 +<code csharp>
 +void Main()
 +{
 +    TaskCompletionSource<Product> taskCompletionSource = new TaskCompletionSource<Product>();
 +    Task<Product> lazyTask = taskCompletionSource.Task;
 +    
 +    Task.Factory.StartNew(() => {
 +        Thread.Sleep(2000);
 +        taskCompletionSource.SetResult(new Product { Id = 1, Name = "Some name" });
 +    });
 +    
 +    Task.Factory.StartNew(() =>
 +    {
 +        if (Console.ReadLine() == "x")
 +        {
 +            Product result = lazyTask.Result;
 +            Console.WriteLine("Result is {0}", result.Name);
 +        }
 +    });
 +    
 +    Thread.Sleep(5000);
 +}
 +
 +class Product
 +{
 +    public int Id { get; set; }
 +    public string Name { get; set; }
 +}
 +
 +</code>
 +
 +===== PLINQ =====
 +
 +Parallel LINQ:
 +
 +  * Automates parallelization
 +  * Considéré déclaratif plutôt qu'impératif
 +  * Opérateurs qui font en sorte que ce n'est pas parallélisé:
 +    * Take, Select, SelectMany, Skip, TakeWhile, SkipWhile, ElementAt
 +  * Anomalies
 +    * Join, GroupBy, GroupJoin, Distinct, Union, Intersect, Except
 +  * Force parallelism:
 +    * .AsParallel().withExecutionMode(ParallelExecution.ForceParallelism)
 +
 +
 +<code csharp>
 +void Main()
 +{
 +    var list = Enumerable.Range(1, 100000);
 +    var primeNumbers = list
 +                        .AsParallel()
 +                        .Where(IsPrime);
 +    Console.WriteLine("{0} prime numbers", primeNumbers.Count());
 +}
 +
 +bool IsPrime(int x)
 +{
 +    if (x == 1) return false;
 +    if (x == 2) return true;
 +    if (x % 2 == 0) return false;
 +    var boundary = (int)Math.Floor(Math.Sqrt(x));
 +
 +    for (int i = 3; i <= boundary; i += 2)
 +    {
 +        if (x % i == 0)
 +        {
 +            return false;
 +        }
 +    }
 +    return true;    
 +}
 +</code>
 +
 +==== Degree of Parallelism ====
 +
 +<code csharp>
 +void Main()
 +{
 +    List<string> websites = new List<string>();
 +    websites.Add("apple.com");
 +    websites.Add("google.com");
 +    websites.Add("microsoft.com");
 +    
 +    List<PingReply> responses = websites
 +                                    .AsParallel()
 +                                    .WithDegreeOfParallelism(websites.Count())
 +                                    .Select(PingSites)
 +                                    .ToList();
 +    
 +    foreach (var response in responses)
 +    {
 +        Console.WriteLine(response.Address + " " + response.Status + " " + response.RoundtripTime);
 +    }
 +    
 +    Console.ReadLine();
 +}
 +
 +private static PingReply PingSites(string websiteName)
 +{
 +    Ping ping = new Ping();
 +    return ping.Send(websiteName);
 +}
 +</code>
 +
 +
 +
  
 ====== Thread Marshalling ====== ====== Thread Marshalling ======
Ligne 1276: Ligne 1524:
   * [[http://bigballofmud.wordpress.com/2009/03/21/thread-marshalling-part-1-creating-a-thread-in-windows-forms/|Thread Marshalling]]   * [[http://bigballofmud.wordpress.com/2009/03/21/thread-marshalling-part-1-creating-a-thread-in-windows-forms/|Thread Marshalling]]
   * [[http://www.albahari.com/threading/|Threading (Joseph Albahari)]]   * [[http://www.albahari.com/threading/|Threading (Joseph Albahari)]]
 +
 +
 +====== Pattern Matching ======
 +
 +<code csharp>
 +void Main()
 +{
 +    var circle = new Circle(5);
 +    var circleRadius100 = new Circle(250);
 +    var rectangle = new Rectangle(420, 1337);
 +    var square = new Rectangle(70, 70);
 +
 +    var shapes = new List<Shape> { circle, circleRadius100, rectangle, square };
 +
 +    var randomShape = shapes[new Random().Next(shapes.Count)];
 +
 +    CSharp6Feature(randomShape);
 +    CSharp7Feature(randomShape);
 +    CSharp8Feature(randomShape);
 +    CSharp9Feature(randomShape);
 +}
 +
 +private void CSharp6Feature(Shape shape)
 +{
 +    Console.WriteLine("=== C# 6 Pattern matching features ===");
 +    if (shape is Circle) // 'is' operator
 +    {
 +        var circle = (Circle)shape;
 +        Console.WriteLine($"Circle with radius {circle.Radius}");
 +    }
 +    else
 +    {
 +        Console.WriteLine($"Shape is something else");
 +    }
 +}
 +
 +private void CSharp7Feature(Shape shape)
 +{
 +    Console.WriteLine("=== C# 7 Pattern matching features ===");
 +
 +    if (shape is Circle circle)  // implicit casting
 +    {
 +        Console.WriteLine($"Circle with radius {circle.Radius}");
 +    }
 +    else
 +    {
 +        Console.WriteLine($"Shape is something else");
 +    }
 +    
 +    // using switch
 +    
 +    switch (shape)
 +    {
 +        case Circle c:
 +            Console.WriteLine($"Circle with radius {c.Radius}");
 +            break;
 +        case Rectangle r when r.Height == r.Width:
 +            Console.WriteLine($"This is a square");
 +            break;
 +        default:
 +            Console.WriteLine($"Shape is something else");
 +            break;
 +    }
 +}
 +
 +private void CSharp8Feature(Shape shape)
 +{
 +    Console.WriteLine("=== C# 8 Pattern matching features ===");
 +
 +    if (shape is Circle { Radius: 10 })
 +    {
 +        Console.WriteLine($"Circle with radius of 10");
 +    }
 +    
 +    var shapeDetails = shape switch
 +    {
 +        Circle => "This is a circle", // we can drop the 'cir' is not used
 +        Rectangle rec when rec.Height == rec.Width => "This is a square",
 +        _ => "Shape is something else"
 +    };
 +}
 +
 +private void CSharp9Feature(Shape shape)
 +{
 +    Console.WriteLine("=== C# 9 Pattern matching features ===");
 +
 +    if (shape is not Rectangle) // 'not' added
 +    {
 +        Console.WriteLine($"This is not a rectangle");
 +    }
 +
 +    if (shape is Circle { Radius: > 100 and < 200, Area: >= 1000 })
 +    {
 +        Console.WriteLine($"Circle with radius greater than 100");
 +    }
 +
 +
 +    // that can be used like so: if (shape is not null) {...}
 +
 +    var shapeDetails = shape switch
 +    {
 +        Circle => "This is a circle", // we can drop the 'cir' is not used
 +        Rectangle rec when rec.Height == rec.Width => "This is a square",
 +        { Area: 100 } => "Area is 100",
 +        _ => "Shape is something else"
 +    };
 +
 +    var areaDetails = shape.Area switch
 +    {
 +        >= 100 and <= 200 => "Area is between 100 and 200",
 +        _ => ""
 +    };
 +    
 +}
 +
 +public static class Extensions
 +{
 +    public static bool IsLetter(this char c) =>
 +        c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';
 +}
 +
 +public abstract class Shape
 +{
 +    public abstract double Area { get; }
 +}
 +
 +public class Rectangle : Shape, ISquare
 +{
 +    public Rectangle(int height, int width)
 +    {
 +        Height = height;
 +        Width = width;
 +    }
 +    
 +    public override double Area => Height * Width;
 +    
 +    public int Height { get; set; }
 +    public int Width { get; set; }
 +}
 +
 +public class Circle : Shape
 +{
 +    private const double PI = Math.PI;
 +    
 +    
 +    public Circle(int diameter)
 +    {
 +        Diameter = diameter;
 +    }
 +
 +    public int Diameter { get; set; }
 +    public int Radius => Diameter / 2;
 +
 +    public override double Area => PI * Radius * Radius;
 +}
 +
 +public interface ISquare
 +{
 +    int Height { get; set; }
 +    int Width { get; set; }
 +}
 +
 +static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
 +    => (groupSize, visitDate.DayOfWeek) switch
 +    {
 +        (<= 0, _) => throw new ArgumentException("Group size must be positive"),
 +        (_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
 +        (>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
 +        (>= 10, DayOfWeek.Monday) => 30.0m,
 +        (>= 5 and < 10, _) => 12.0m,
 +        (>= 10, _) => 15.0m,
 +        _ => 0.0m
 +    };
 +
 +</code>
 +
 +
 +
  
 ====== Reactive ====== ====== Reactive ======
developpement/dotnet/csharp/introduction.1696432984.txt.gz · Dernière modification : 2023/10/04 17:23 de sgariepy