异步等待 Task.WhenAll(tasks);卡住了,不会继续代码

Async await Task.WhenAll(tasks); stuck, won't continue with code

提问人:Rumix 提问时间:8/11/2023 最后编辑:Rumix 更新时间:8/12/2023 访问量:94

问:

现在是早上 7 点,不是那种好人。我累了,我有意大利面条代码,我只想解释一下。一般是第一次合作。代码如下:async

namespace TargetFinder
{
    public class AsyncRandomIP
    {
        private const string BaseFolderName = "TargetLocatorData/AsyncRandomIP";
        private const string FoundIPsFileName = "found_ips.txt";
        private const string UnreachableIPsFileName = "unreachable_ips.txt";

        public static async Task ScanAsync(Config config, int port, int amount,
            Form1 form, CancellationToken cancellationToken)
        {
            string baseFolderPath = Path.Combine(Environment.GetFolderPath(
                Environment.SpecialFolder.Desktop), BaseFolderName);
            Methods.EnsureDirectoryExists(baseFolderPath);

            var random = new Random();
            var unreachableIPs = Methods.LoadIPsFromFile(UnreachableIPsFileName,
                baseFolderPath);
            var foundIPs = Methods.LoadIPsFromFile(FoundIPsFileName, baseFolderPath);

            var ipQueue = new BlockingCollection<string>();
            for (int i = 0; i < amount; i++)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                if (config.AllowRepeatScans)
                {
                    ipQueue.Add(Methods.GenerateRandomIPAddress(random));
                }
                else
                {
                    string ipAddress;

                    do
                    {
                        ipAddress = Methods.GenerateRandomIPAddress(random);
                    } while (unreachableIPs.Contains(ipAddress));
                    ipQueue.Add(ipAddress);
                    form.UpdateConsole("NewQueueSet: " + ipQueue);
                }
            }

            int concurrentThreads = config.ConcurrentThreads;
            var tasks = new List<Task>();

            for (int i = 0; i < concurrentThreads; i++)
            {
                tasks.Add(Task.Run(async () =>
                {
                    foreach (string ipAddress in ipQueue
                        .GetConsumingEnumerable(cancellationToken))
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            return;
                        }

                        await ProcessIPAsync(config, port, unreachableIPs,
                            foundIPs, baseFolderPath, form, ipAddress);
                    }
                }));
            }
            form.UpdateConsole(Environment.NewLine + "Waiting for finish:");
            try
            {
                await Task.WhenAll(tasks);
                Console.WriteLine("Finished");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                form.UpdateConsole(
                    Environment.NewLine + "IPs with requested service:");
                foreach (string ip in foundIPs)
                {
                    form.UpdateConsole(Environment.NewLine + ip);
                }
            }
        }

        private static async Task ProcessIPAsync(Config config, int port,
            HashSet<string> unreachableIPs, HashSet<string> foundIPs,
            string baseFolderPath, Form1 form, string ipAddress)
        {
            if (Methods.IsIPReachable(ipAddress))
            {
                using (TcpClient client = new TcpClient())
                {
                    try
                    {
                        client.SendTimeout = config.ClientSendTimeoutMilliseconds;
                        await client.ConnectAsync(ipAddress, port);

                        form.UpdateConsole(Environment.NewLine + $"IP: {ipAddress},
                            Service found: true");

                        foundIPs.Add(ipAddress);
                        Methods.SaveIPsToFile(foundIPs, FoundIPsFileName,
                            baseFolderPath);
                    }
                    catch (SocketException)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        form.UpdateConsole(Environment.NewLine + $"IP: {ipAddress},
                            Service found: false");
                        Console.ForegroundColor = ConsoleColor.White;

                        foundIPs.Add(ipAddress);
                        Methods.SaveIPsToFile(foundIPs, FoundIPsFileName,
                            baseFolderPath);
                    }
                }
            }
            else
            {
                form.UpdateConsole(
                    Environment.NewLine + $"IP: {ipAddress}, Not reachable");
                unreachableIPs.Add(ipAddress);
                Methods.SaveIPsToFile(unreachableIPs, UnreachableIPsFileName,
                    baseFolderPath);
            }
        }
    }
}

我无法弄清楚任务在哪里冻结和未完成,控制台没有多大用处,ChatGPT 也没有多大用处。如果有人可以检查一下并让我知道,那么我写这篇文章的方式就会受到批评,而不是我最自豪的项目。如果有人能帮忙,我将不胜感激。

其他 form1 代码。

namespace TargetFinder
{
    public partial class Form1 : Form
    {
        private SynchronizationContext uiContext;
        private CancellationTokenSource cancelTokenSource;
        public Form1()
        {
            InitializeComponent();
            uiContext = SynchronizationContext.Current;
            cancelTokenSource = new CancellationTokenSource();
        }

        private void label10_Click(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            thread_tb.Text = Convert.ToString(thread_trackbar.Value);
            if (print_res_bt.Checked)
            {
                format_bt.Enabled = true;
            }
            else
            {
                format_bt.Enabled = false;
            }
        }

        private void Button2_Click(object sender, EventArgs e)
        {
            thread_tb.Text = "4";
            thread_trackbar.Value = 4;
            amount_tb.Text = "50";
            timeout_tb.Text = "3000";
            print_res_bt.Checked = true;
            format_bt.SelectedItem = ".TXT";

        }

        private void configurationToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void print_res_bt_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void directoryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            directory_set.ShowDialog();
        }

        private void scan_button_Click(object sender, EventArgs e)
        {
            try
            {
                int port = Convert.ToInt32(port_tb.Text);
                int amount = Convert.ToInt32(amount_tb.Text);

                cancelTokenSource = new CancellationTokenSource(); // Reset CancellationTokenSource

                Info.Main(port, amount, this, cancelTokenSource.Token);
            }
            catch (OperationCanceledException)
            {
                console.AppendText(Environment.NewLine + "Scan cancelled.");
            }
        }
        public void UpdateConsole(string text)
        {
            uiContext.Post(new SendOrPostCallback(delegate
            {
                console.AppendText(text);
            }), null);
        }

        private void cancel_button_Click(object sender, EventArgs e)
        {
            cancelTokenSource.Cancel();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            console.Text = "";
        }

        private void set_btn_Click(object sender, EventArgs e)
        {
            int clientSendTimeoutMilliseconds = Convert.ToInt32(timeout_tb.Text);
            int concurrentThreads = Convert.ToInt32(thread_tb.Text);
            bool allowRepeatScans = repeat_scan_bt.Checked;
            ConfigManager.SetConfig(clientSendTimeoutMilliseconds, concurrentThreads, allowRepeatScans);
            MessageBox.Show("Configuration updated.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
}
C# WinForms 异步 async-await 任务并行库

评论

2赞 Panagiotis Kanavos 8/11/2023
neither is chatgpt为什么你认为统计生成的文本会有所帮助?
3赞 Panagiotis Kanavos 8/11/2023
WhenAll不会冻结,只有在所有任务完成时才会完成。使用 时,枚举不会完成,直到发布者使用 完成枚举。异步代码不一定是意大利面条代码。将发布者和订阅者分隔到单独的类中,并使用适当的类。异步发布/订阅集合是 Channel<T>,而不是 .任务不是线程,而是承诺。 通过负责创建工作线程并将项目传递给他们,消除了问题中的大量代码GetConsumingEnumerableCompleteAddingBlockingCollectionParallel.ForEachAsync
1赞 RQDQ 8/11/2023
这确实是意大利面条代码。看起来您正在将 Windows 窗体对象传递到执行大量异步工作的方法中。我强烈建议将此代码 ( ) 与 UI 位分开。处理调度程序协调是一项艰巨的任务。ScanAsync
2赞 Guru Stron 8/11/2023
我在任何地方都看不到电话。另外,我不确定这里是否需要它,像应该这样的东西就可以了。ipQueue.CompleteAdding();Parallel.ForEachAsync
1赞 Panagiotis Kanavos 8/12/2023
代码的编写方式根本没有理由使用。使用普通的 List 或 Queue,然后使用多个任务处理结果。默认情况下,同时处理的项数与核心数一样多。您可以通过 options 参数进行更改BlockingQueueawait Parallel.ForEachAsync(list,async (item,ct)=>await someMethod(item,ct))

答: 暂无答案