【问题标题】:My async task is blocking other code from running and not outputting anything我的异步任务阻止其他代码运行并且不输出任何内容
【发布时间】:2022-02-27 16:38:11
【问题描述】:

最近我一直在将我的 node.js 机器人转换为 C#,但由于某种奇怪的原因,我遇到了一个问题 public async Task InitCloudCompute() 阻止我的其他代码运行。我不知道为什么会发生这种情况,而且我对 C# 还很陌生。如果有人能帮我解决这个问题,我将不胜感激。 :)

编辑:我忘了说程序启动了,因为我可以在浏览器中打开本地主机。

using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using static Doom.Grid.Bot.Utility.ConsoleGlobals;

namespace Doom
{
    class Program
    {
        static void Main(string[] args) => new Program().InitBotAsync()
            .GetAwaiter().GetResult();
        
        private DiscordSocketClient _client;
        private CommandService _commands;
        private IServiceProvider _services;

        public async Task InitBotAsync()
        {
            _client = new DiscordSocketClient();
            _commands = new CommandService();
            _services = new ServiceCollection()
                .AddSingleton(_client)
                .AddSingleton(_commands)
                .BuildServiceProvider();

            _client.Log += _client_internal_Log;

            await InitCloudCompute();
            await RegisterCommandsAsync();
            await _client.LoginAsync(TokenType.Bot, "Nope"); // TODO: Remove 
                // hard-coded token
            await _client.StartAsync();
            await Task.Delay(-1);
        }

        public async Task InitCloudCompute()
        {
            Console.WriteLine($"{CCServiceInternalLog} Initializing CCService");
            ProcessStartInfo processStartInfo;
            Process process;

            processStartInfo = new ProcessStartInfo
            {
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardInput = true,
                UseShellExecute = false,
                Arguments = "-console -verbose 5000",
                FileName = "D:\\21CC\\CC-FE4FEB09A756\\CCService.exe"
            };

            process = new Process
            {
                StartInfo = processStartInfo,
                EnableRaisingEvents = true
            };

            process.OutputDataReceived += new DataReceivedEventHandler
            (
                delegate (object sender, DataReceivedEventArgs e)
                {
                    Console.WriteLine($"{CCServiceInternalLog} {e.Data.ToString()}");
                }
            );

            process.Start();
            process.BeginOutputReadLine();
            process.WaitForExit();
            process.CancelOutputRead();
        }

        private Task _client_internal_Log(LogMessage arg)
        {
            Console.WriteLine($"{DiscordInternalLog} {arg}");
            return Task.CompletedTask;
        }

        public async Task RegisterCommandsAsync()
        {
            _client.MessageReceived += HandleCommandAsync;
            await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
        }

        private async Task HandleCommandAsync(SocketMessage arg)
        {
            var message = arg as SocketUserMessage;
            var context = new SocketCommandContext(_client, message);
            if (message.Author.IsBot) return;

            int argPos = 0;
            if (message.HasStringPrefix(">", ref argPos))
            {
                var result = await _commands.ExecuteAsync(context, argPos, _services);
                if (!result.IsSuccess) Console.WriteLine(result.ErrorReason);
            }
        }
    }
}

【问题讨论】:

  • 使主函数也异步。
  • @Fildor 我会尽力告诉你进展如何
  • 那么static async Task Main(string[] args) { await new Program().InitBotAsync(); } 应该可以工作了。
  • .GetResult() 很可能是您的阻塞问题的根源。然后await 会解决这个问题。
  • 好吧,WaitForExit() 怎么样了? InitCloudCompute() 没有任何异步。编译时应该有一个警告。

标签: c# asynchronous async-await blocking .net-4.6.1


【解决方案1】:

根据此处的文档https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.waitforexit?view=net-6.0 Process.WaitForExit 会阻塞当前线程。

“设置等待关联进程退出的时间段,并阻塞当前执行线程,直到时间过去或进程退出。为避免阻塞当前线程,请使用Exited事件。”

Task.GetAwaiter 的文档同样说它通常用于编译器而不是用于应用程序。 https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.getawaiter?view=net-6.0

所以你可以创建一个新任务并像这样运行它

Task task = Task.Run({new Program().InitBotAsync()});

// And instead of process.WaitForExit() try

process.Exited += new EventHandler(yourHandlerHere);

进行清理

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-23
    • 2020-10-08
    相关资源
    最近更新 更多