2013-06-21 126 views
8

我有一個處理while循環中的對象的隊列。他們是異步的地方加入..這樣的:動態C#對象的設計模式

myqueue.pushback(String value); 

而且他們都是這樣處理的:

while(true) 
{ 
    String path = queue.pop(); 
    if(process(path)) 
    { 
     Console.WriteLine("Good!"); 
    } 
    else 
    { 
     queue.pushback(path); 
    } 
} 

現在,事情是,我想修改該支持TTL樣(生存時間)標誌,所以文件路徑將被添加超過n次。

我怎麼能這樣做,同時保持bool process(String path)函數簽名?我不想修改它。

我想過要拿着一張地圖或者一個列表來計算進程函數返回false的次數爲多少次,並且在第n次返回false時從列表中刪除路徑。我想知道如何能夠更加動態地完成這項工作,並且最好我希望TTL在每次新增加該流程時自動減量。我希望我不是在說垃圾。 也許使用這樣的事情

class JobData 
{ 
    public string path; 
    public short ttl; 

    public static implicit operator String(JobData jobData) {jobData.ttl--; return jobData.path;} 
} 
+1

你認爲你的'JobData'方法有什麼錯誤? –

+0

好的事情是我不想修改過程函數,我只想'JobData'對象能夠在c#中對String進行隱式轉換,並且有一些想法可以動態地並且隱含地減少tll值 – AlexandruC

+0

可能的附加我會提到但不認可的解決方案是使用TTL計數器向String類型添加擴展方法。不理想或不推薦,因爲它增加了一個無意義的方法來處理字符串(甚至侷限於本地命名空間),但它會解決您的具體問題。 –

回答

2

我喜歡JobData類的想法,但已經有了一個答案,證明了這一點,並且您使用文件路徑的事實爲您提供了另一個可能的優勢。某些字符在文件路徑中無效,因此您可以選擇一個用作分隔符。這裏的優點是隊列類型仍然是一個字符串,因此您不必修改任何現有的異步代碼。你可以在這裏看到保留的路徑中的字符列表:

http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words

對於我們而言,我會用百分比(%)字符。然後,你可以修改代碼如下,沒有別的需要改變:

const int startingTTL = 100; 
const string delimiter = "%"; 

while(true) 
{ 
    String[] path = queue.pop().Split(delimiter.ToCharArray()); 
    int ttl = path.Length > 1?--int.Parse(path[1]):startingTTL; 

    if(process(path[0])) 
    { 
     Console.WriteLine("Good!"); 
    } 
    else if (ttl > 0) 
    { 
     queue.pushback(string.Format("{0}{1}{2}", path[0], delimiter,ttl));    
    } 
    else 
    { 
     Console.WriteLine("TTL expired for path: {0}" path[0]); 
    } 
} 

再次,從一個純粹的架構角度看,具有兩個屬性的類是更好的設計...但是從實際情況來看,YAGNI :這個選項意味着您可以避免返回並更改其他推入隊列的異步代碼。該代碼仍然只需要知道字符串,並將與此未修改。

還有一件事。我想指出的是,這是一個相當緊密的循環,很容易與CPU核心競爭。此外,如果這是.Net隊列類型,並且緊密循環比異步生成領先於清空隊列,則會拋出一個異常,該異常將跳出while(true)塊。你可以解決代碼這兩個問題是這樣的:

while(true) 
{ 

    try 
    { 
     String[] path = queue.pop().Split(delimiter.ToCharArray()); 
     int ttl = path.Length > 1?--int.Parse(path[1]):startingTTL; 

     if(process(path[0])) 
     { 
      Console.WriteLine("Good!"); 
     } 
     else if (ttl > 0) 
     { 
      queue.pushback(string.Format("{0}{1}{2}", path[0], delimiter,ttl));    
     } 
     else 
     { 
      Console.WriteLine("TTL expired for path: {0}" path[0]); 
     } 
    } 
    catch(InvalidOperationException ex) 
    { 
     //Queue.Dequeue throws InvalidOperation if the queue is empty... sleep for a bit before trying again 
     Thread.Sleep(100); 
    } 
} 
1

你可以抽象/封裝的「作業管理器」的功能。隱藏來電者的隊列和實施,這樣你就可以做任何你想做的事情,而不需要來電者的照顧。類似這樣的:

public static class JobManager 
{ 
    private static Queue<JobData> _queue; 

    static JobManager() { Task.Factory.StartNew(() => { StartProcessing(); }); } 

    public static void AddJob(string value) 
    { 
     //TODO: validate 

     _queue.Enqueue(new JobData(value)); 
    } 

    private static StartProcessing() 
    { 
     while (true) 
     { 
      if (_queue.Count > 0) 
      { 
       JobData data = _queue.Dequeue(); 
       if (!process(data.Path)) 
       { 
        data.TTL--; 
        if (data.TTL > 0) 
         _queue.Enqueue(data); 
       } 
      } 
      else 
      { 
       Thread.Sleep(1000); 
      } 
     } 
    } 

    private class JobData 
    { 
     public string Path { get; set; } 
     public short TTL { get; set; } 

     public JobData(string value) 
     { 
      this.Path = value; 
      this.TTL = DEFAULT_TTL; 
     } 
    } 

} 

然後你的處理循環可以處理TTL值。

編輯 - 添加了一個簡單的處理循環。此代碼不是線程安全的,但應該有希望給你一個想法。

+1

原始問題說:「我怎麼能做到這一點,同時保持布爾過程(字符串路徑)功能簽名?」。我不知道我看到'process(String path)'適合你的代碼...... – Chris

+1

這仍然在處理循環內 –

+1

像這樣使用'Thread.Sleep()'是一個壞主意。有一個永遠不會返回的'static'構造函數是一個非常糟糕的主意。 – svick

2

如果約束是bool process(String path)不能觸及/更改然後把功能集成到myqueue。您可以保留其公共簽名void pushback(string path)string pop(),但在內部您可以跟蹤您的TTL。您可以將字符串路徑包裝到類似JobData的類中,該類可以添加到內部隊列中,也可以按路徑鍵入第二個Dictionary。也許甚至像保存最後的pop ed路徑一樣簡單,並且如果後續push是相同的路徑,則可以假定它是拒絕/失敗的項目。另外,在你的pop方法中,你甚至可以丟棄一個已經被拒絕了太多時間的路徑,並且在內部獲取下一個路徑,所以調用代碼很幸福地不知道這個問題。

+0

鑑於推送代碼的異步性質,將推送與最後一個流行音樂匹配似乎是一個非常糟糕的主意。 –

+0

是的,這是真的。可能最好堅持使用包裝數據結構。 – tcarvin