如何并行访问多个用户的方法 [英] How to get parallel access to the method for multiple users

查看:47
本文介绍了如何并行访问多个用户的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的电报机器人是必要的,以便用户可以按顺序回答问题,并以相同的顺序为特定用户并行保存这些答案.

My telegram bot is necessary so that the user can answer questions in order and save these answers in the same order for a specific user in parallel.

static readonly ConcurrentDictionary<int, string[]> Answers = new ConcurrentDictionary<int, string[]>();

static void Main(string[] args)
        {
            try
            {
                Task t1 = CreateHostBuilder(args).Build().RunAsync();
                Task t2 = BotOnMessage();
                await Task.WhenAll(t1, t2);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }

        }

这是我的 BotOnMessage() 方法来接收和处理来自用户的消息

here is my BotOnMessage() method to receive and process messages from users

async static Task BotOnMessage()
        {
            int offset = 0;
            int timeout = 0;

            try
            {
                await bot.SetWebhookAsync("");
                while (true)
                {
                    var updates = await bot.GetUpdatesAsync(offset, timeout);

                    foreach (var update in updates)
                    {
                        var message = update.Message;

                        if (message.Text == "/start")
                        {
                            Registration(message.Chat.Id.ToString(), message.Chat.FirstName.ToString(), createdDateNoTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
                            var replyKeyboard = new ReplyKeyboardMarkup
                            {
                                Keyboard = new[]
                                {
                                    new[]
                                    {
                                        new KeyboardButton("eng"),
                                        new KeyboardButton("ger")
                                    },
                                }
                            };

                            replyKeyboard.OneTimeKeyboard = true;

                            await bot.SendTextMessageAsync(message.Chat.Id, "choose language", replyMarkup: replyKeyboard);
                        }

                        switch (message.Text)
                        {
                            case "eng":
                                var replyKeyboardEN = new ReplyKeyboardMarkup
                                {
                                    Keyboard = new[]
                                {
                                    new[]
                                    {
                                        new KeyboardButton("choice1"),
                                        new KeyboardButton("choice2")
                                    },
                                }
                                };
                                replyKeyboardEN.OneTimeKeyboard = true;
                                await bot.SendTextMessageAsync(message.Chat.Id, "Enter choice", replyMarkup: replyKeyboardEN);
                                await AnonymEN();
                                break;

                            case "ger":
                                var replyKeyboardGR = new ReplyKeyboardMarkup
                                {
                                    Keyboard = new[]
                                {
                                    new[]
                                    {
                                        new KeyboardButton("choice1.1"),
                                        new KeyboardButton("choice2.2")
                                    },
                                }
                                };
                                replyKeyboardGR.OneTimeKeyboard = true;
                                await bot.SendTextMessageAsync(message.Chat.Id, "Enter choice", replyMarkup: replyKeyboardGR);
                                await AnonymGR();
                                break;
                        }

                       
                        offset = update.Id + 1;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }

        }

AnonymEN() 方法用于 switch 中的 eng 案例.当我从 BotOnMessage() 中的 switch case 调用此方法时,问题出现在这里.直到 switch (message.Text) 多个用户可以异步发送消息并得到响应.当第一个用户输入 AnonymEN() 时,第二个用户无法从这个方法得到响应,直到第一个用户完成它直到结束.此外,我在 AnonymEN() 的末尾调用 BotOnMessage() 以返回初始点,并有可能再次启动机器人.对于问题和答案的有序结构,我从这里使用 ConcurrentDictionary 方式 保存发送给bot的用户消息并将完成的表单发送给其他用户.关于如何编辑代码以使此机器人同时可供多个用户使用的任何建议和解决方案?

and AnonymEN() method for eng case in switch. The problem appears here when I call this method from switch case in BotOnMessage(). Until switch (message.Text) multiple users can asynchronously send messages and get response. When first user enters AnonymEN() second user can't get response from this method until first user will finish it till the end. Also I call BotOnMessage() in the end of AnonymEN() to get back for initial point with possibility to start bot again. For the ordered structure of questions and answers I used ConcurrentDictionary way from here Save user messages sent to bot and send finished form to other user. Any suggestion and solution how to edit code to make this bot available for multiple users at one time?

async static Task AnonymEN()
        {
            int offset = 0;
            int timeout = 0;

            try
            {
                await bot.SetWebhookAsync("");
                while (true)
                {
                    var updates = await bot.GetUpdatesAsync(offset, timeout);

                    foreach (var update in updates)
                    {
                        var message = update.Message;

                        int userId = (int)message.From.Id;

                        if (message.Type == MessageType.Text)
                        {
                            if (Answers.TryGetValue(userId, out string[] answers))
                            {
                                var title = message.Text;

                                if (answers[0] == null)
                                {
                                    answers[0] = message.Text;
                                    await bot.SendTextMessageAsync(message.Chat, "Enter age");

                                }
                                else
                                {
                                    SaveMessage(message.Chat.Id.ToString(), "anonym", "anonym", "anonym", answers[0].ToString(), title.ToString(), createdDateNoTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
                                    Answers.TryRemove(userId, out string[] _);
                                    await bot.SendTextMessageAsync(message.Chat.Id, "ty for request click /start");
                                    await BotOnMessage();
                                }
                            }
                            else if (message.Text == "choice1")
                            {
                                Answers.TryAdd(userId, new string[1]);
                                await bot.SendTextMessageAsync(message.Chat.Id, "Enter name");
                            }
                        }
                        offset = update.Id + 1;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }

        }

推荐答案

我可以看到您的代码存在多个问题:

I can see multiple issues with your code:

  1. 很难阅读.虽然这是个人偏好,但我强烈建议编写具有 1 个职责的简短方法.这将使您更容易理解和维护您的代码.https://en.wikipedia.org/wiki/Single-responsibility_principle

一切都是静态的.这使得跟踪每个用户应该跟踪的任何状态(例如语言)变得非常困难.

Everything is static. This makes it very hard to keep track of any state such as language that should be tracked per user.

使用无转义的无限循环和递归.我非常怀疑这是有意为之,但您可能会得到像这样的无限调用链 BotOnMessage ->AnonymEN ->BotOnMessage ->匿名EN.我认为您想使用 returnbreakwhile(someVar) 方法退出 AnonymEN 函数调用 BotOnMessage 函数.

Using infinite loops and recursion with no escape. I highly doubt this was intended but you could get an infinite chain of calls like this BotOnMessage -> AnonymEN -> BotOnMessage -> AnonymEN. I think you want to exit the AnonymEN function using either a return, break or while(someVar) approach instead of calling the BotOnMessage function.

如果有两个用户发送消息,您会得到不同的响应.示例消息流 user1:/start, user1: eng, user2: hello.机器人现在将向 user2 提供英文响应.我确定这不是故意的

If two users are sending messages you get mixed responses. Example message flow user1: /start, user1: eng, user2: hello. The bot will now give an english response to user2. I'm sure this is not intended

下面的代码是解决我提到的问题的最小示例.这不是完美的代码,但应该可以帮助您入门.

The code below is a minimal example that addresses the issues I mentioned. It is not perfect code but should help you get started.

private Dictionaty<string, UserSession> userSessions = new ();

async Task BotOnMessage()
{
  try
  {
    while(true)
    {
      var message = await GetMessage(timeout);
      var userSession = GetUserSession(message.user);
      userSession.ProcessMessage(message);
     }
  }
  catch(){}
}

async void GetUserSession(string user)
{
  if(!userSessions.HasKey(user))
  {
    userSessions[user](new Session());
  }
  return userSessions[user];
}

public class UserSession
{
  public async Task ProcessMessage(message)
  {
    // Existing message processing code goes here. 
    // Do not use a loop or recursion.
    // Instead track the state (e.g. languge) using fields.
  }
}

这篇关于如何并行访问多个用户的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆