工作队列
(使用java客户端)
在第一个教程中我们从命名的队列写了发送和接受信息的程序。在这个教程我们将创建在多个工作者中被用来分发时间消耗任务的工作队列。
工作队列(又名:任务队列)背后的主要的思想是避免立即做一些资源密集型的任务,并且必须等待它完成。相反,我们安排稍后完成。我们将任务封装成一个消息,并将它发送到队列中,一个工作者进程在后台运行将会弹出任务然后最终执行工作。当你运行许多工作者,这些工作将会被它们分享。
这个概念在有可能处理复杂的,一个短的http请求的任务的web运用中是特别有用的。
准备
在先前部分的教程中我们发送一个包含“Hello World!”的消息。现在我们将发送代表复杂任务的字符串。我们没有真实的任务,像要被调整大小的图像或者渲染的pdf文件,所以让我们假装我们很忙--通过使用Threed.sleep()方法。我们将字符串中的点数当作它的复杂度,每一个点代表一秒的工作,列如,一个假的任务描述成Hello...将执行3秒。我们将从先前的例子中稍微修改下Send.java的代码,为了允许从命令行中发送任意的消息,这个程序将安排任务到工作队列中,我们命名为NewTask.java
String message = getMessage(argv);
channel.basicPublish("", "hello", null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
一些帮助从命令行参数获取信息。
private static String getMessage(String[] strings){
if (strings.length < 1)
return "Hello World!";
return joinStrings(strings, " ");
}
private static String joinStrings(String[] strings, String delimiter) {
int length = strings.length;
if (length == 0) return "";
StringBuilder words = new StringBuilder(strings[0]);
for (int i = 1; i < length; i++) {
words.append(delimiter).append(strings[i]);
}
return words.toString();
}
旧的Recv.java程序也需要一些改变,需要为消息中的每个点假装1秒钟的工作,将会处理传送消息和执行任务,我们称作Worker.java
final Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
}
}
};
boolean autoAck = true; // acknowledgment is covered below
channel.basicConsume(TASK_QUEUE_NAME, autoAck, consumer);
我们的假任务模拟执行时间:
private static void doWork(String task) throws InterruptedException {
for (char ch: task.toCharArray()) {
if (ch == '.') Thread.sleep(1000);
}
}
像教程1一样编译它们(和工作目录中的jar文件和环境变量cp)
javac -cp $CP NewTask.java Worker.java
循环分发:
使用任务队列的优点之一是能够轻松地平行工作如果我们创建一个积压的工作,我们可以添加更多的工作者并且这种方式容易扩展。
首先,我们尝试同时运行两个工作者,他们都从队列中获取消息但是,如何,让我们看下。你需要打开三个控制台,两个运行工作者程序这些控制台将是我们的两个消费者-C1,C2
# shell 1
java -cp $CP Worker
# => [*] Waiting for messages. To exit press CTRL+C
# shell 2
java -cp $CP Worker
# => [*] Waiting for messages. To exit press CTRL+C
在第三个控制台,我们将发布新的任务,一旦我们开始消费者,你可以发布一些消息
# shell 3
java -cp $CP NewTask
# => First message.
java -cp $CP NewTask
# => Second message..
java -cp $CP NewTask
# => Third message...
java -cp $CP NewTask
# => Fourth message....
java -cp $CP NewTask
# => Fifth message