2012-11-16 72 views
0

爲什麼我真的需要這樣:(在底部的問題簡單的描述,在EDIT3)如何組織多線程與隊列和睡覺

讓我們想象一下,我試圖創建應用程序的嘰嘰喳喳。它具有儘可能多的帳戶,因爲我現在要添加或更高版本(例如10)。因此,對於每個帳戶,我們有一個選項:

  1. twite from rss;
  2. 關注人;
  3. 轉發任何twites。

當我們談論一個帳戶時,每個任務都應該在後臺工作,並在其他任務中同步。對於某一賬戶來說,一次不會有太多的並且正在進行(太多的請求)。

Okey,這意味着我必須在一段時間內爲每個賬戶只做一個任務。這是否意味着,我必須爲此刻的每個活動帳戶組織一個線程?但是,線程是什麼,告訴每個帳戶接下來要做什麼(填滿隊列)?一個帳戶要twite,另一隻retwites並遵循人:

  1. (線程1)賬戶答:想從RSS /文件整天twites;
  2. (線程2)賬戶B:想每30秒轉換一次,並且每15分鐘跟蹤一次;
  3. (線程3):應該填滿「帳戶A」的隊列(使雙方成爲對方,使雙方);
  4. (線程4):應該填滿「帳戶B」的隊列(使得轉發,進行轉發(在15分鐘之內,每30秒)...跟隨人,使轉發...);

在這種情況下,當每個帳戶一個線程只是做的工作(這是什麼在queue->事實也的確如此),另一隻是填補了隊列,我可以在我的功能手動添加任務(現在,所有的我的accs,重做這個twite或跟隨這個人), - 在每個隊列中,我會添加一個新任務,然後儘可能快地執行每個線程。因此,我的目標(目標)是創建一個應用程序,每個帳戶都應該完成他的工作,並且我可以選擇告訴他們,下一步該怎麼做(改變他們的任務優先級)。

我想問你,我是正確的約每線程2線程,關於隊列(也許它應該是一個全局隊列,其中線程將他們的任務使用帳戶,作爲標記(分隔符)),也許,你可以給我一些關於我的任務的建議。

編輯: 還有最大的問題,如果我做20個賬戶,但將只有5線程(極限) - 所以它不應該是1 ACC-> 2線程,這應該是1個線程填滿隊列(看起來像是全局的)和其他工作 - 但是他們可以爲一個帳戶工作(一個線程成雙向,另一個線程開始跟隨用戶),並且這使得我處於一個角落, - 不能理解,我應該如何組織所有這些線程。

編輯2:還有一個問題:執行時間。我應該檢查每個線程時間,當執行任務時應該執行(計劃下一個小時的任務)(現在23:55,這個任務將在23:59執行, - 接下來是什麼?跳過?睡眠?)。

如果我不應該檢查時間和隊列添加任務,準備好執行,我再次遇到一個帳戶的問題 - 一個任務(設置添加15秒延遲,添加20秒延遲,跟隨人60秒延遲)=>每分鐘我將有3個任務在隊列中,但應該只執行一個(我有100個帳戶,但只有5個工作線程(他們應該互相同步,現在什麼帳戶任務執行其他線程?))。

Edit3(讓我們變得簡單): Okey,讓我們忘掉twitter吧。我將編寫Windows桌面應用程序,它應該在控制檯中寫入東西(讓它成爲'來自Bob的','來自Bob的','來自Bob的再見')。

我可以多名字我的程序添加(鮑勃,傑克,約翰,大衛,斯科特),並檢查,哪些詞組這個名字應該寫:

  1. 鮑勃只寫「你好,從鮑勃」每15秒;
  2. 傑克每隔1分鐘給傑克寫'你好,'每5秒給傑克寫'再見';
  3. John從'John'寫下'hello','hi','bye'+,5秒,10秒,15秒 秒;
  4. e.t.c. (讓它成爲20個名字);

我希望這是okey?所以,現在,當我開始我的應用程序時,這20個名字中的每一個都應該在控制檯中寫下它們的短語,但是在它們的時間和所有線程中(讓它限制10個工作線程) - 應該是任務每個名字一個任務(如果一個線程現在正在寫'來自Jack的'hello',其他人不應該'從Jack'寫'再見',即使這個任務應該在01:42:00執行,只有當一個任務完成了Jack ,其他開始)。 (+)另外,我應該有一個選項,爲這個名字中的某個人添加一個選項,以便隨着他們最近的任務完成,儘快寫出我想要的任何短語。

我希望我能找到你的幫助。

Edit4:這樣:enter image description here

THX的幫助,現在我知道我需要什麼,以及如何安排我的應用程序。

最後實現:

我做了用自己的代碼解決方案我的任務,我看起來像最好的。

enter image description here

所以,當我生成我的隊列,每個帳戶,並把他們的應用程序的任務之一全局隊列,我將它傳遞給TimerCallBack功能,入住是否有任何排隊準備執行任務(但只檢查event_elements [0]), - 如果是這樣,set 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)。

所以,這對我的作品很大;)

+0

很難理解你所說的一般想法。您正在製作一個可同時在多個Twitter帳戶上執行操作的Windows Form應用程序?你能告訴我們更多關於這個應用程序嗎?這是一個用戶在他的機器上的桌面應用程序嗎?這是一個服務器應用程序?你爲什麼擔心太多的任務? – Jason

+0

我已經添加了簡單的描述,我正在努力解決的問題 – user1612334

+0

我仍然可以很難理解你在說什麼。這聽起來像是與「賬戶」和線程有關,每個賬戶有一個線程......或者是你的問題是什麼?我不確定你的具體問題是什麼。但是,你看過任務並行庫嗎?它使任務和線程(特別是只能在另一個完成後才能運行的任務)非常簡單。 – Jason

回答

0

我的第一個傾向是使用優先級隊列和Timer。這是我該怎麼做的。

首先,創建一個全局Stopwatch來維持應用程序的時間。您不希望夏令時或其他時間更改混亂您的時間,因爲這可能會導致您在兩次事件之間等待太久或使事件發生得太快。所以,冥冥之中你有:

static Stopwatch ApplicationTime = Stopwatch.StartNew(); 

您也有一個Account類,它包含有關Twitter的帳戶信息,最重要的是,該帳戶的最後一個採取行動的時間:

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>(); 

不幸的是,沒有內置在.NET運行庫優先級隊列類。如果你做了谷歌搜索,你可以找到幾個。我多年前寫的一篇是http://www.devsource.com/c/a/Languages/A-Priority-Queue-Implementation-in-C/。您可以從http://mischel.com/pubs/priqueue.zip獲取最新消息。請注意,我的優先隊列不是併發的;你必須在它周圍包裝一個併發層。出於你的目的,在以任何方式訪問隊列之前,一個簡單的lock應該就足夠了。

現在,如何使用所有的東西:

比方說,你要檢查的賬戶每次30分鐘。您將創建一個新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)); 
} 

因爲你可以有一個帳戶多個事件,事件處理是一個有點複雜,但不是過度。您必須根據帳戶上次活動時間檢查當前時間。如果最後一個事件太近,那麼在事件時間中添加一些時間,並在新時間內將其放回隊列中。

要處理一個項目,您可以啓動一個異步Web請求(我會建議的),使用BackgroundWorker或者觸發一個TPL Task。關鍵在於,當異步請求完成時,完成回調所做的最後一件事是更新下一個事件的時間並將該事件放回隊列中。

我已經在這裏掩蓋了一些細節,但我認爲你可以收集到基本的想法:至少足以開始。

+0

Thx爲你的答案,但我不明白什麼ApplicationTime.Elapsed意味着代碼= \ – user1612334

+0

,我沒有TimeSpan.Infinite在我的C#。你的意思是TimeSpan.MaxValue? – user1612334

+0

看起來我明白你的意思... – user1612334