C# 如何使用队列和睡眠组织多线程

C# 如何使用队列和睡眠组织多线程,c#,winforms,twitter,C#,Winforms,Twitter,为什么我真的需要这个:(底部的问题简单描述,在edit3下) 让我们想象一下,我试图为twitter创建应用程序。它的帐户数和我现在或以后添加的帐户数一样多(例如10个)。因此,对于每个客户,我们都有一个选择: 来自rss的twite 跟随人们 再给我一根树枝 当我们谈论一个帐户时,每个任务都应该在后台工作,并在其他帐户内同步。对于其中一个帐户,一次不会有twite和跟踪(太多请求) 好的,这意味着,我必须在一个时间内每个帐户只做一个任务。这是否意味着,我必须为这个时刻帐户中的每个活动组织一个线

为什么我真的需要这个:(底部的问题简单描述,在edit3下)

让我们想象一下,我试图为twitter创建应用程序。它的帐户数和我现在或以后添加的帐户数一样多(例如10个)。因此,对于每个客户,我们都有一个选择:

  • 来自rss的twite
  • 跟随人们
  • 再给我一根树枝
  • 当我们谈论一个帐户时,每个任务都应该在后台工作,并在其他帐户内同步。对于其中一个帐户,一次不会有twite和跟踪(太多请求)

    好的,这意味着,我必须在一个时间内每个帐户只做一个任务。这是否意味着,我必须为这个时刻帐户中的每个活动组织一个线程?但线程是什么,告诉每个帐户下一步要做什么(填满队列)?一个帐户想要twitter,另一个只是重复并跟踪用户:

  • (线程1)帐户A:想要整天从RSS/文件推特
  • (线程2)帐户B:希望每30秒重试一次,每15分钟跟踪一次用户
  • (线程3):应该填充“帐户A”的队列(make twite,make twite,make twite)
  • (线程4):应该填充“帐户B”的队列(生成retwite,生成retwite(在15分钟内,每30秒一次)…跟踪人员,生成retwite 在这种情况下,当每个帐户的一个线程刚刚开始工作(队列中的内容->他是这样做的)而另一个线程刚刚填满队列时,我可以添加我的功能手动任务(现在,我所有的账户,重新编辑这个twite或跟随这个人),-在每个队列中,我会添加一个新任务,每个线程都会尽快执行,尽可能的

    因此,我的目标是制作一个应用程序,每个客户都应该在其中工作,我可以选择告诉他们下一步要做什么(更改他们的任务优先级)

    我想问你们,每个acc大约2个线程对吗,关于队列(也许它应该是一个全局队列,其中线程使用帐户作为标记(分隔符))执行任务,也许你们可以给我一些关于我的任务的建议

    编辑: 最大的问题是,如果我有20个帐户,但只有5个线程(限制)-所以它不应该是1个acc->2个线程,应该是1个线程来填充队列(看起来像是全局的),另一个线程用于工作-但是他们可以为一个帐户工作(一个线程生成twite,其他线程开始跟踪用户),这让我陷入了困境-我不明白,我该如何组织所有这些线索

    Edit2:还有一个问题:执行时间。我是否应该在每个线程时间签入,何时执行任务(计划下一个小时的任务)(现在23:55,这个任务将在23:59执行,-下一步是什么?跳过?睡眠?)

    如果我不检查时间,在队列中只添加任务,这就可以执行了,我又出现了一个帐户一个任务的问题(设置add twite 15秒延迟,add retwite 20秒延迟,follow people 60秒延迟)=>每分钟我将有3个任务在队列中,但应该逐个执行(我有100个帐户,但只有5个工作线程)(它们应该彼此同步,什么帐户任务现在执行其他线程?)

    Edit3(让它变得简单): 好吧,让我们忘掉twitter吧。我将要编写windows桌面应用程序,它应该在控制台中编写一些东西(让它成为“Bob你好”、“Bob你好”、“Bob再见”)

    我可以在我的程序中添加许多名字(鲍勃、杰克、约翰、戴夫、斯科特),然后检查这些名字应该写什么短语:

  • Bob每15秒只写一次“Bob你好”
  • 杰克每1分钟写一次“杰克你好”,每5秒写一次“杰克再见”
  • 约翰写“你好”,“你好”,“再见”+从“约翰”开始,5秒,10秒,15秒 秒
  • e、 t.c.(设为20个名称)
  • 我希望,没问题吧

    所以,现在,当我启动我的应用程序时,这20个名称中的每一个都应该在控制台中编写它们的短语,但要在它们的时间内完成,并且对于所有线程(让它限制为10个工作线程)-任务应该是每个名称一个任务(如果一个线程现在正在写“hello from Jack”,那么另一个线程不应该写“bye from Jack”,即使这个任务应该在01:42:00执行。只有当Jack的一个任务完成时,其他线程才会启动)

    (+)另外,我应该有一个选项,让这个名字中的某个人在完成他们最接近的任务后,尽快写出我想要的任何短语

    我希望,我会找到你的帮助

    Edit4:so:

    Thx的帮助,现在我知道我需要什么,以及如何组织我的应用程序

    最终实现:

    我已经用自己的代码完成了任务,对我来说,这个解决方案看起来是最好的

    因此,当我为每个帐户生成队列并将它们放入应用程序任务的一个全局队列中时,我将其传递给TimerCallBack函数,该函数检查队列中是否有任何准备执行的任务(但仅检查事件元素[0]),如果是,则设置isactive=true(对于个人队列,请防止在上一个事件完成之前执行下一个事件),并放置此队列,该队列应在迭代后的每个第一个事件中执行

    然后,将其作为集合传递给Parallel.ForEach:

     Parallel.ForEach(readyToExec, new ParallelOptions { MaxDegreeOfParallelism = 5 }, eq =>
                {
                    lock (eq)
                    {
                        QueueElement exec_elem = eq.elements[0];
                        Console.WriteLine(exec_elem.timeToExecute + ": " + eq.account.Name + " " + exec_elem.EventType);
                        exec_elem.timeToExecute = DateTime.Now + exec_elem.timeDelay;
                        eq.timeLastExecute = DateTime.Now;
                        eq.elements.Sort();
                        eq.isactive = false;
                    }
                });
    
    顺便说一下,在添加要执行的事件之前添加了检查:

            foreach (var equeue in queue)
            {
                if (!equeue.isactive && equeue.elements[0].readyToExecute)
                {
                    if (DateTime.Now > equeue.timeLastExecute + TimeSpan.FromSeconds(5))
                    {
                        equeue.isactive = true;
                        readyToExec.Add(equeue);
                    }
                    else
                    {
                        equeue.elements[0].timeToExecute = DateTime.Now + TimeSpan.FromSeconds(5);
                    }
                }
            }
    
    要手动延迟执行一个帐户的事件(例如,如果在00:00:00中写入“Hello”,则在00:00:05之前无法开始执行下一个事件,即使执行时间为00:00:02)


    所以,它对我来说非常有效;)

    我的第一个倾向是使用优先级队列和优先级队列。下面是我的做法

    首先,创建一个全局
    秒表
    ,以维护应用程序时间。您不希望夏令时或其他时间更改打乱您的计时,因为这可能会导致您在事件之间等待太长时间或使事件发生得太快。因此,您可以:

    static Stopwatch ApplicationTime = Stopwatch.StartNew();
    
    class Account
    {
        // information about the account goes here
    
        public TimeSpan LastEventTime { get; set; }
    }
    
    class AccountEvent
    {
        public Account acct { get; private set; }
        public TimeSpan dueTime { get; set; }
        public ActionType action { get; private set; } // follow, re-tweet, etc.
    
        // constructor, etc.
    }
    
    PriorityQueue<TimeSpan, AccountEvent> EventQueue = new Priority<TimeSpan, AccountEvent>();
    
    var ev = new AccountEvent(userAccount, ApplicationTime.Elapsed.AddMinutes(30), ActionType.Follow);
    EventQueue.Enqueue(ev.dueTime, ev);
    
    Timer eventTimer = new System.Threading.Timer(QueueProc, null, TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(-1));
    
    void QueueProc(object state)
    {
        while (eventQueue.Count > 0 && eventQueue.Peek().dueTime < ApplicationTime.Elapsed)
        {
            AccountEvent ev = eventQueue.Dequeue();
            // process item. See comments below.
        }
        // reset the timer so that it will fire in five seconds
        eventTimer.Change(TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(-1));
    }