【问题标题】:How to let OkHttpClient.Dispatcher consume okhttp3.Request in LIFO(last in first out) order?如何让 OkHttpClient.Dispatcher 以 LIFO(后进先出)顺序使用 okhttp3.Request?
【发布时间】:2020-02-28 14:20:40
【问题描述】:

目标:

最后入队的okhttp3.Call首先执行


尝试过的解决方案:LIFO Executor(不起作用)

我找到了 LIFO Executor(Executor Service with LIFO ordering) 的解决方案,并通过这种方式将这种 Executor 应用到 OkHttpClient

private val httpClient = OkHttpClient.Builder().dispatcher(
        Dispatcher(ThreadPoolExecutor(..., LifoLinkedBlockingDequeue<Runnable>()))
    ).build()

但是,这不起作用

分析

okhttp3.Dispatcher追踪源码后发现:

  1. 首先,每个入队的Call 被添加到(private final Deque&lt;AsyncCall&gt; readyAsyncCalls = new ArrayDeque&lt;&gt;()) 中的Dispatcher.java"
  2. 然后,那些Calls 从readyAsyncCalls 移动到Executor 的阻塞双端队列中以FIFO 顺序
  3. 最后,Executor 中的Calls 以​​LIFO顺序执行

在我的例子中,大量的Calls 是同时产生的,并且消耗它们的线程相对较少。
--> 大多数Calls 暂时排在Dispatcher 而不是Executor
--> LIFO Executor 不起作用

示例

| Dispatcher: 1,2,3,4,5 | Executor:    | executing:    | done:          |
| Dispatcher: 2,3,4,5   | Executor:1   | executing:    | done:          |
| Dispatcher: 4,5       | Executor:2,3 | executing:1   | done:          |
| Dispatcher: 5         | Executor:4   | executing:3,2 | done:1         |
| Dispatcher:           | Executor:5   | executing:4   | done:1,3,2     |
| Dispatcher:           | Executor:    | executing:5   | done:1,3,2,4   |
| Dispatcher:           | Executor:    | executing:    | done:1,3,2,4,5 |
  • Calls 以先进先出的顺序从Dispatcher 移动到Executor,这个过程非常“低效”。
  • Executor 到执行状态的Calls 以LIFO 顺序排列。但是Executor中的Calls很少,LIFO效果不明显。

有没有人知道其他方法来实现这一点?

【问题讨论】:

    标签: android okhttp requestdispatcher lifo


    【解决方案1】:

    我发现将请求从 Dispatcher 移动到 Executor 的原因是:一次移动的请求数有两个最大值。

    // okhttp3.Dispatcher
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        //do something...    
    
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
        //do something...
    }
    

    溶胶

    Dispatcher.maxRequestsDispatcher.maxRequestPerHost 设置更大的值

    这样每个新的传入请求都可以尽快移动到执行器
    --> 充分发挥传入Executor的队列特征

    但是...我不确定较大的最大值是否会导致任何副作用...

    【讨论】:

      【解决方案2】:

      在 OkHttp 的调度程序前构建您自己的 LIFO 队列。它接受调用并保持它们直到它们准备好被执行。当它们出现时,将它们发布在调度程序上。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-02
        • 2017-01-26
        • 1970-01-01
        • 1970-01-01
        • 2012-06-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多