Java - 如何在一次发送一定数量的http请求的同时排队等待其他请求 [关闭] 。

问题描述 投票:1回答:1

我正在开发一个discord机器人,它可以让你使用知乎的API来搜索myanimelist的动漫。然而,该API每秒只允许2个请求,任何违反该请求的行为都将导致IP禁令。因此,我必须对搜索功能(将请求发送到知乎API)进行编程,使其只能同时搜索两样东西。然而,这比看起来要复杂得多。

对于那些不知道Discord API是如何工作的人来说,有一个被覆盖的消息接收方法,当一个用户在包含机器人的服务器上发送消息时,这个方法就会被运行。这个方法也有点像线程,因为每个发送消息的用户都会有一个单独的实例运行。

这使程序变得复杂,因为如果超过3个用户同时搜索一个动漫,我需要以某种方式发送两个请求,同时对第三个请求进行排队,直到另外两个用户中的一个返回响应。但是这样一来,我还得把响应返回给实例的 messageReceived 方法发送的。

enter image description here

对于这个问题,我没有任何代码可以展示。我只是希望能得到一个解释,伪代码,或者java代码来解决这个问题。非常感谢您

java httprequest discord
1个回答
1
投票

我不知道我是否完全理解了你的问题,但似乎你可以用消费者生产者模式解决这个问题,中间有一个阻塞队列。

因此,当用户发送消息时,它不会直接进入知乎API,而是作为一个任务提交到一个阻塞队列中。这将是应用的生产者部分。

消费者部分将通过接收队列中的任务(用户消息)并发送请求来完成向Jihan Rest API的提交。

你可以通过将Callable提交到一个有两个线程的约束线程池中,确保每秒只提交和返回两个请求。由于Callable会阻塞直到完成,所以你可以在两者之间计时一秒.或者你可以使用像semaphore这样的同步器,这将是一个更好的做法。


0
投票

我看到ilot的回复,我同意他的建议。他已经提到使用semaphores是个好主意,我想我可以分享一个使用该库的Java例子。我没有任何使用Discord的经验,但希望你或其他人会觉得这个例子很有用。

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    final static int TOTAL_REQUESTS = 10;
    final static int MAX_SIMULTANEOUS_REQUESTS = 2;
    final Semaphore semaphore;
    // the purpose of this array is for synchronization of the demo only
    final Thread[] threads = new Thread[TOTAL_REQUESTS];

    public static void main(String[] args) throws InterruptedException {
        new SemaphoreDemo().start();
    }

    SemaphoreDemo() {
        semaphore = new Semaphore(MAX_SIMULTANEOUS_REQUESTS);
    }

    void start() throws InterruptedException {
        System.out.printf("Start sending...             [permits = %d]\n", semaphore.availablePermits());

        // trigger incoming messages
        for (int i = 0; i < TOTAL_REQUESTS; i++) {
            messageReceived(new Request(i));
        }

        // synchronize with threads
        for (int i = 0; i < TOTAL_REQUESTS; i++) {
            threads[i].join();
        }

        System.out.println("Done!");
    }

    void messageReceived(Request request) {
        RequestHandler requestHandler = new RequestHandler(request, semaphore);
        Thread thread = createThread(request.i, requestHandler);
        thread.start();
    }

    Thread createThread(int i, RequestHandler requestHandler) {
        threads[i] = new Thread(requestHandler);
        return threads[i];
    }
}

class Request {
    final int i;

    Request(int i) {
        this.i = i;
    }

    void sendHttpRequest() {
        // do your thing
    }

    @Override
    public String toString() {
        return "Request " + i;
    }
}

class RequestHandler implements Runnable {
    final Request request;
    final Semaphore semaphore;

    RequestHandler(Request request, Semaphore semaphore) {
        this.request = request;
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            // try to acquire one of the permits if available, else wait...
            semaphore.acquire();

            System.out.printf("%s: sending request   [permits = %d]\n", request, semaphore.availablePermits());

            // Simulate sending a request with a random response time between 0 and 3 seconds
            request.sendHttpRequest();
            Thread.sleep(Math.round(3000 * Math.random()));

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // the request succeeded or was interrupted; always release the permit so another request can take it 
            semaphore.release();
            System.out.printf("%s: received response [permits = %d]\n", request, semaphore.availablePermits());
        }
    }
}

这个例子模拟了使用一个只有2个许可的旗语的10个同时请求。这意味着当所有的许可都被占用时,剩下的线程如果想从旗语中获取许可,就必须等待其中一个许可被释放。

我得到的一个结果是这样的。

Start sending...             [permits = 2]
Request 0: sending request   [permits = 1]
Request 1: sending request   [permits = 0]
Request 1: received response [permits = 1]
Request 2: sending request   [permits = 0]
Request 2: received response [permits = 1]
Request 3: sending request   [permits = 0]
Request 0: received response [permits = 1]
Request 4: sending request   [permits = 0]
Request 3: received response [permits = 1]
Request 5: sending request   [permits = 0]
Request 4: received response [permits = 1]
Request 6: sending request   [permits = 0]
Request 5: received response [permits = 1]
Request 7: sending request   [permits = 0]
Request 6: received response [permits = 1]
Request 8: sending request   [permits = 0]
Request 8: received response [permits = 1]
Request 9: sending request   [permits = 0]
Request 9: received response [permits = 1]
Request 7: received response [permits = 2]
Done!

需要注意的是,请求可能会按顺序完成, 但总是会有0到2个可用的许可。

© www.soinside.com 2019 - 2024. All rights reserved.