Как разрешить OkHttpClient.Dispatcher использовать okhttp3.Request в порядке LIFO (последний пришел первым вышел)? - PullRequest
0 голосов
/ 02 ноября 2019

Цель:

Последний в очереди okhttp3.Call выполняется первым


Пробное решение: LIFO Executor (не работает)

Я нашел решениедля LIFO Executor ( Служба Исполнителя с упорядочением LIFO ) и таким образом применил Executor в OkHttpClient таким образом

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

Но это не работал .

Анализ

После отслеживания исходного кода в okhttp3.Dispatcher я обнаружил, что:

  1. Во-первых, каждый в очереди Callдобавляется в (private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>()) в Dispatcher.java "
  2. Затем эти Call перемещаются из readyAsyncCalls в блокирующую деку Executor в FIFO порядке
  3. Наконец, Call с в Executor выполняются в LIFO порядке

В моем случае одновременно выдаются огромные Call с, итам относительно меньше потоков, потребляющих их. -> Большинство Call в очереди в 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 |
  • Call с перемещаются с Dispatcher на Executor в порядке FIFO,и эта процедура очень "неэффективна".
  • Call s от Executor до состояния выполнения в порядке LIFO. Но в Executor мало Call с, эффект LIFO неочевиден.

Кто-нибудь знает другой способ добиться этого?

Ответы [ 2 ]

1 голос
/ 03 ноября 2019

Создайте свою собственную очередь LIFO перед диспетчером OkHttp. Он принимает вызовы и удерживает их, пока они не будут готовы к выполнению. Когда они есть, опубликуйте их в диспетчере.

0 голосов
/ 04 ноября 2019

Я обнаружил, что причина, по которой НЕОБХОДИМО переместить запросы с 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...
}

Sol

Установить большее значение для Dispatcher.maxRequests и Dispatcher.maxRequestPerHost

, чтобы каждый новый входящий запрос мог быть перемещен исполнителю как можно скорее. -> дать полный охват характеристике очереди, переданной в Executor

Но ... я не уверен, что большой максимум вызовет какие-либо побочные эффекты ...

...