1 सवाल: Console.SetCursorPosition का उपयोग करते हुए एसिंक्रोनस रूप से

पर बनाया गया सवाल Thu, Apr 4, 2019 12:00 AM

कंसोल में प्रगति आइटम के प्रतिशत को अपडेट करने के लिए प्रयोग करने के लिए, मैंने एक छोटा परीक्षण कंसोल एप्लिकेशन बनाया है:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleProgressTest
{
    class Program
    {
        public class ConsoleItem
        {
            public string Item { get; set; }
            public int ConsoleLocLeft { get; set; }
            public int ConsoleLocTop { get; set; }
        }

        static void Main(string[] args)
        {
            List<string> tempList = GenerateTempList();
            List<string> selection = GetSelectionFromList(tempList);

            List<ConsoleItem> consoleItems = new List<ConsoleItem>();
            foreach (string item in selection)
            {
                Console.Write($"Selected: \"{item}\" ");

                ConsoleItem consoleItem = new ConsoleItem()
                {
                    Item = item,
                    ConsoleLocLeft = Console.CursorLeft,
                    ConsoleLocTop = Console.CursorTop
                };
                consoleItems.Add(consoleItem);

                Console.Write("\n");
            }

            int finalCursorLeft = Console.CursorLeft;
            int finalCursorTop = Console.CursorTop;

            Console.CursorVisible = false;
            List<Task> progressTasks = new List<Task>();
            foreach (ConsoleItem item in consoleItems)
            {
                Task itemTask = IncrementProgress(item);
                progressTasks.Add(itemTask);
            }

            Task.WaitAll(progressTasks.ToArray());

            Console.CursorVisible = true;
            Console.SetCursorPosition(finalCursorLeft, finalCursorTop);
            Console.WriteLine("All progress finished. Press any key to exit");
            Console.Read();
        }

        private static List<string> GenerateTempList()
        {
            List<string> result = new List<string>()
            {
                "Item 0",
                "Item 1",
                "Item 2",
                "Item 3",
                "Item 4",
                "Item 5"
            };

            return result;
        }

        public static List<string> GetSelectionFromList(List<string> listToDisplay)
        {
            foreach (string item in listToDisplay)
                Console.WriteLine("(" + listToDisplay.IndexOf(item) + ") " + item);

            Console.WriteLine("Which # would you like?");
            string input = Console.ReadLine();
            List<string> result = new List<string>();
            foreach (string indexStr in input.Split(','))
            {
                if (indexStr.Contains("-"))
                {
                    int startOfRange = Convert.ToInt32(indexStr.Split('-')[0]);
                    int endOfRange = Convert.ToInt32(indexStr.Split('-')[1]);
                    for (int i = startOfRange; i <= endOfRange; i++)
                    {
                        if (i < 0 || i > listToDisplay.Count - 1)
                        {
                            Console.WriteLine("Could not find index " + i);
                            continue;
                        }

                        result.Add(listToDisplay[i]);
                    }
                }
                else
                {
                    int index = Convert.ToInt32(indexStr);
                    if (index < 0 || index > listToDisplay.Count - 1)
                    {
                        Console.WriteLine("Could not find index " + index);
                        continue;
                    }

                    result.Add(listToDisplay[index]);
                }
            }

            return result;
        }

        public static async Task IncrementProgress(ConsoleItem item)
        {
            Random r1 = new Random((int)DateTime.Now.Ticks);
            int millisecondDelay = r1.Next(1000, 5000);

            Random r2 = new Random((int)DateTime.Now.Ticks);
            int percentage = 0;
            while (percentage < 100)
            {
                await Task.Run(() => Thread.Sleep(millisecondDelay));
                percentage = r2.Next(percentage, 101);
                UpdatePercentange(item, percentage);
            }
        }

        private static void UpdatePercentange(ConsoleItem item, double percentage)
        {
            Console.SetCursorPosition(item.ConsoleLocLeft, item.ConsoleLocTop);
            Console.Write($"({percentage}%)");
        }
    }
}

मैंने कंसोल को अपडेट करते समय कुछ अजीब देखा है:

रिकॉर्डिंग 1

(ध्यान दें कि आइटम 2 के 96% तक पहुंचने पर प्रक्रिया कभी-कभी दोहराई जाती है)

लेकिन अगर मैं अपने Debug.WriteLine की शुरुआत में 0600350991100101035062 इस तरह से डालूं:

UpdatePercentage

तब यह ठीक काम करता है:

रिकॉर्डिंग 2

कोई भी विचार जो इसका कारण हो सकता है?

    
0
1 उत्तर                              1                         

आप किसी सामान्य ऑब्जेक्ट (ऑब्जेक्ट सिंक = नई ऑब्जेक्ट () पर्याप्त है) का उपयोग करके अपने अपडेट अनुरोधों को लॉक कर सकते हैं जो आपकी समस्या को रोक देगा।

वर्तमान में, यह वही होता है:

  • (थ्रेड 1) SetCursorPosition
  • (थ्रेड 2) SetCursorPosition (कर्सर अब वह जगह है जहां कभी थ्रेड दो लिखना चाहते हैं)
  • (थ्रेड 1 या 2) Console.Write
  • (दूसरा धागा) Console.Write

ताकि आपका कंसोल आउटपुट ऐसा दिख सके:

private static void UpdatePercentange(ConsoleItem item, double percentage)
{
    Debug.WriteLine($"Updating percentage of {item.Item} at {item.ConsoleLocLeft}, {item.ConsoleLocTop} ({percentage})");
    Console.SetCursorPosition(item.ConsoleLocLeft, item.ConsoleLocTop);
    Console.Write($"({percentage}%)");
}
    
2
2019-04-04 16: 22: 08Z
  1. आह, उन विस्तृत चरणों से वास्तव में यह समझना आसान हो जाता है कि क्या हो रहा है। और उदाहरण के लिए धन्यवाद!
    2019-04-04 16: 26: 22Z
        private static object _sync = new object();
    
        private static void UpdatePercentange(ConsoleItem item, double percentage)
        {
            lock(_sync)
            {   
                Console.SetCursorPosition(item.ConsoleLocLeft, item.ConsoleLocTop);
                Console.Write($"({percentage}%)");
            }
        }
    
स्रोत रखा गया यहाँ