Bonjour,

Je dois compresser une liste de quelques centaines de fichiers au format GZip.

Le serveur sur lequel ça tourne dispose de 16 coeurs.

J'ai fait un programme mono-threadé, donc ça bouffe au max 6% du CPU, ce qui est loin d'être optimum.

Je souhaite donc modifier mon programme de façon à traiter en // plusieurs fichiers.

Je saurai lancer la compression de TOUS les fichiers en même temps à l'intérieur d'une boucle.
Sauf que j'ai pas franchement envie de planter le serveur : je doute fortement que ce soit une bonne idée de lancée plusieurs centaines de threads en même temps.

Ce que je souhaite faire, c'est une file d'attente contenant tous les fichiers, et n'en traiter que X en // (avec X = nb core - 1 par exemple).

Seulement, je ne m'en sors pas.

Voici (une partie) de mon code :
Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
 
            // Main
            List<FileInfo> FilesToCompress = null;
            FilesToCompress = GetAllFiles();
            var t = Task.Run(() => AsyncCompressAllFiles(FilesToCompress));
            t.Wait();
 
 
        public static void CompressFile(FileInfo fileToCompress)
        {
            using (FileStream originalFileStream = fileToCompress.OpenRead())
            {
                Console.WriteLine("Compressing {0}.", fileToCompress.FullName);
                using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz"))
                {
                    using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionLevel.Optimal))
                    {
                        originalFileStream.CopyTo(compressionStream);
                    }
                }
                FileInfo info = new FileInfo(fileToCompress.FullName + ".gz");
                Console.WriteLine("Compressed {0} from {1} to {2} bytes.", fileToCompress.FullName, fileToCompress.Length.ToString(), info.Length.ToString());
            }
            fileToCompress.Delete();
        }
 
        public static async Task AsyncCompressFile(FileInfo fileToCompress)
        {
            await Task.Run(() => CompressFile(fileToCompress));
        }
 
        public async static void CompressAllFiles(List<FileInfo> filesToCompress)
        {
            TaskQueue queue = new TaskQueue();
            foreach (FileInfo fileToCompress in filesToCompress)
            {
                await queue.Enqueue(()=>AsyncCompressFile(fileToCompress));
            }
        }
 
     public class TaskQueue
    {
        private SemaphoreSlim semaphore;
        public TaskQueue()
        {
            if (Environment.ProcessorCount <= 1)
            {
                semaphore = new SemaphoreSlim(1);
            }
            else if (Environment.ProcessorCount > 32)
            {
                semaphore = new SemaphoreSlim(31);
            }
            else
            {
                semaphore = new SemaphoreSlim(Environment.ProcessorCount - 1);
            }
 
        }
 
        public async Task Enqueue(Func<Task> taskGenerator)
        {
            await semaphore.WaitAsync();
            try
            {
                await taskGenerator();
            }
            finally
            {
                semaphore.Release();
            }
        }
    }

J'ai trouvé la classe TaskQueue sur un forum, et elle semble, de ce que j'en comprends, faire ce que je veux.

Au détail près que lors de son appel, un seul thread est lancé à la fois.
Sur ma machine de dev qui a 4 processeurs logiques, je m'attends à en vois 3 tourner en même temps...