2009-04-24 56 views
1

我正在開發一個應用程序,發出請求的MusicBrainz web服務。我在MusicBrainz的手動閱讀不使超過每秒一個請求到web服務或客戶機的IP將被阻止。時間受限服務

您建議使用哪種體系結構,以便使此限制對服務客戶端透明。

  • 我想調用一個方法(例如getAlbuns),它只應該在最後一次請求後1秒發出請求。
  • 我也想立刻撥打10請求和服務應該處理的排隊,返回結果時繳費(非阻塞)。

謝謝!

+0

我假設你正在創建一個桌面應用程序? – 2009-04-24 01:56:19

+0

是的,沒錯! – 2009-04-25 06:53:09

回答

1

,我建議一個java.util.Timerjava.util.concurrent.ScheduledThreadPoolExecutorTimer非常簡單,並且完全適合這個用例。但是,如果額外的調度要求,後來查明,單Executor可以處理所有的人。無論哪種情況,都使用固定延遲方法,而不是固定比率方法。

循環任務polls請求對象的併發隊列。如果有未決請求,任務執行它,並通過回調返回結果。服務查詢和要調用的回調是請求對象的成員。

應用程序保留對共享隊列的引用。要安排請求,只需將其添加到隊列中即可。


只是爲了說明,如果執行計劃任務時隊列爲空,則不會發出請求。簡單的方法就是結束任務,調度程序將在一秒鐘後調用該任務再次檢查。

但是,這意味着即使最近沒有處理任何請求,啓動任務也可能需要一秒鐘的時間。如果這種不必要的延遲是不能容忍的,那麼編寫自己的線程可能優於使用TimerScheduledThreadPoolExecutor。在您自己的定時循環中,如果您選擇阻塞空隊列,直到請求可用,您可以更好地控制調度。內置的定時器,不能保證等待上一次執行完一整秒;他們一般安排相對開始時間的任務。

如果第二種情況是您的想法,那麼您的run()方法將包含一個循環。每次迭代在隊列上由blocking開始,直到收到請求,然後記錄時間。處理完請求後,再次檢查時間。如果時間差小於1秒,則剩餘時間爲sleep。該設置假定在一個請求的開始和下一個請求之間需要一秒延遲。如果在一次請求結束和下一次請求結束之間需要延遲,則不需要檢查時間;只是睡一秒鐘。

還有一點需要注意的是,該服務可能能夠在單個請求中接受多個查詢,這將減少開銷。如果是這樣,通過在take()上對第一個元素進行阻塞,然後使用poll()(可能具有非常短的阻塞時間(5ms左右))來查看應用程序是否提出了更多請求。如果是這樣,這些可以捆綁在對服務的單個請求中。如果queueBlockingQueue<? extends Request>,它可能是這個樣子:

Collection<Request> bundle = new ArrayList<Request>(); 
    bundle.add(queue.take()); 
    while (bundle.size() < BUNDLE_MAX) { 
     Request req = queue.poll(EXTRA, TimeUnit.MILLISECONDS); 
     if (req == null) 
     break; 
     bundle.add(req); 
    } 
    /* Now make one service request with contents of "bundle". */ 
1

您需要定義本地客戶端將調用的本地「代理服務」。

本地代理將接收請求並將其傳遞給實際服務。但僅限於每秒一封郵件的速度。

你是如何做到這一點,取決於你可以使用的tecnoligy。

最簡單的將是一個靜態的一個mutithreaded Java服務和LastRequestTime長的同步。」時間戳變量(雖然你會需要一些代碼雜技保持順序您的要求)

一個更復雜的服務可能有。由於調用之間所需的延遲的工作線程接收請求,並把它們放在一個隊列的單個線程拿起請求,並通過他們到真正的服務。