Queues

Names

Queues 有名字,这样应用才能引用它们。
应用可能自己取名或者让broker为它生活吃呢过一个名字。Queue名字最多可包含255个字节的UTF-8字符。
以“amq.”开头的queue名字是broker内部预留的。试图违反规则声明一个这样名字的queue 会导致一个channel级的异常,返回码为403(ACCESS_REFUSED

Server-named Queues

在AMQP 0-9-1中,broker可以代表应用生成唯一的队列名称。要使用此功能,请将空字符串作为队列名称参数传递:通过使用需要队列名称的空字符串,可以通过同一通道中的后续方法获取相同的生成名称。这是有效的,因为channel会记住上次服务器生成的队列名称。

Properties

queue拥有定义它的行为的属性值。下面是一组必要属性和一个可选择的map:
Name
Durable(queue将在broker重启后继续存在)
Exclusive(仅由一个连接使用,并且该连接关闭时将删除队列)
Auto-delete(当最后一个consumer取消订阅时,至少有一个consumer的queue被删除)
Arguments(可选的,由插件和特定与broker的功能使用,例如消息TTL,队列长度限制等)

Declaration and Property Equivalence

在一个队列可以使用之前,必须声明它。声明队列将导致它创建(如果它不存在)。如果队列已经存在并且其属性与声明中的属性相同,则声明将不起作用。如果现有队列属性与声明中队列属性不同时,将引发具有代码406(PRECONDITION_FAILED)的channel级异常。

Optional Arguments

可选的queue参数,也称为"x-arguments"。因为它们在AMQP 0-9-1协议中的字段名称是一个map(字典),可以在声明队列时由客户端提供。它们由插件和特定于broker的功能使用,例如

  • Message and queue TTL
  • Queue length limit
  • Mirroring settings
  • Max number of priorities
  • Consumer priorities
    等等。

可选参数可以通过两种方式提供:
使用策略的队列组(推荐)
当客户端声明一个queue时,以每个队列为基础(On a per-queue basis when a queue is declared by a client,水平有限,不会翻译。。。)

前一种选择更灵活,非侵入性,不需要修改和重新部署应用程序。因此,强烈建议大多数用户使用。

客户端提供可选参数的方式因client library到client library而异,但通常是在durable,auto_delete和声明queue的函数的其他参数之后的下一个参数。

Message Ordering

RabbitMQ中的队列是有序的消息集合。message以FIFO方式入队出队,尽管优先级队列,分片队列和其他功能可能会影响这种方式。

Durability

持久化队列持久化到磁盘中,因此可以在broker重启后继续运行。不持久的队列称为瞬态。并非所有场景和用例都要求队列持久。
队列的持久性不会使路由到该队列的message持久。如果broker被删除后重新启动,则在代理启动期间将重新声明持久队列,但是只会恢复持久性message。

Temporary Queues

对于一些工作负载,队列应该是短暂的。虽然客户端可以在断开连接之前删除它们声明的队列,但这并不总是很方便。最重要的是,客户端连接可能会失败,可能会留下未使用的资源(队列)。

有三种方式可以自动删除队列:
Exclusive queues
TTLs
Auto-delete queues

当其最后一个消费者被取消时(如,使用AMQP 0-9-1中的basic.cancel)或者已经消失(关闭的通道或连接,或者于server的TCP连接丢失),将自动删除队列。

如果队列从未有任何消费者,如,当使用basic.get方法(“Pull” API)发生所有消费时,它将不会自动删除。对于这种情况,请使用exclusive queue或者 queue TTL

Exclusive Queues

exclusive queue只能通过其声明连接来使用(消耗,清洗,删除等)。尝试使用来自不同连接的exclusive queue将导致通道级异常RESOURCE_LOCKED,并显示一条错误消息:cannot obtain exclusive access to locked queue.

当其声明连接关闭或消失时(如,由于底层TCP连接丢失),将删除exclusive queue。因此,它们仅适用于client特定的瞬态。
通常使用服务器命名的exclusive queue。

Mirrored and Distributed Queues

队列可以跨集群节点进行复制,并通过松散耦合的节点或集群进行联合。请注意,镜像和联合是正交特征,不应视为直接替代。

Time-to-Live and Length Limit

Queue可以拥有长度限制。Queue和message也可以拥有TTL(time to live)。
这两个功能都可以用于数据到期,并且可以限制队列最多可以使用多少资源(RAM,磁盘空间),例如:当consumer离线或其吞吐量落后于publisher时。

In Memory and Durable Storage

队列将消息保存在RAM和/或磁盘上。在一些协议(例如AMQP 0-9-1)中,这由客户端部分地控制。在AMQP 0-9-1中,这是通过消息属性(delivery_mode,或在某些客户端,persistent)完成的。
将消息发布为瞬态表明RabbitMQ应该在RAM中保留尽可能多的消息。但是,当队列发现自己处于内存压力之下时,队列甚至会将瞬态消息写入磁盘。
路由到持久队列的持久消息将分批或者在经过一定时间后(几分之一秒)保留。
无论持久性属性如何,Lazy queue都会将消息更积极地输出到磁盘

Priorities

queue可以拥有0个或更多优先级。此功能是选择性加入:只通过可选参数配置的具有最大优先级的队列才会优先。
publisher使用消息属性中的priority 字段指定message优先级。
如果需要优先级队列,我们建议使用1到10之间。目前使用更多优先级将消耗更多资源(Erlang 进程)。

CPU Utilisation and Parallelism Considerations

目前,单个队列(主服务器或镜像服务器)仅限于其热代码路径上的单个CPU核心。因此,该设计假设大多数系统在实践中使用多个队列。单个队列通常被认为是反模式的(并且不仅仅是出于资源利用的原因)。
如果需要权衡消息排序的并行性(更好的CPU核心利用率),rabbitmq-sharding 提供了一种对client透明的方式。

Metrics and Monitoring

RabbitMQ收集有关队列的多个指标。其中大多数都可以通过RabbitMQ HTTP API和管理UI获得,它是专为监控而设计的。这包括队列长度,入口和出口速率,消费者数量,各种状态下的消息数量(例如准备交付或未确认),RAM中与磁盘上的消息数量等等。
可以使用管理UI中的rabbitmq-top插件和单个队列页面来访问运行时指标,例如VM调度程序使用,队列(Erlang)进程GC活动,队列进程使用的RAM量,队列进程邮箱长度。

Consumers and Acknowledgments

可以通过注册使用者(订阅)来消费消息,这意味着RabbitMQ将消息推送到客户端,或者单独获取支持此消息的协议(例如basic.get AMQP 0-9-1方法),类似于HTTP GET。
一旦将传递写入连接套接字,消费者就可以明确地或自动地确认传递的消息。
自动确认模式通常会提供更高的吞吐量和更少的网络带宽。然而,当遇到失败时,它提供的保证最少。根据经验,首先考虑使用手动确认模式。

Prefetch and Consumer Overload

自动确认模式也可以压倒消费者,消费者无法在交付消息时尽快处理消息。这可能导致消费者进程的内存使用和/或OS切换的永久性增长。
手动确认模式提供了一种设置未完成(未确认)交付数量限制的方法:信道QoS(预取)。
使用更高(数千或更多)预取级别的消费者可能会遇到与使用自动确认的消费者相同的过载问题。
大量未确认的消息将导致代理更高的内存使用量。

Message States

入队消息通常处于两种状态之一:
准备交付
已交付但还未被consumer确认

Determining Queue Length

可以通过多种方式确定队列长度:
使用AMQP 0-9-1,在queue.declare方法响应(queue.declare-ok)上使用属性。字段名称为message_count。访问方式因客户端库到客户端库而异。
使用RabbitMQ HTTP API。
使用rabbitmqctl list_queues命令。

队列长度定义为准备传递的消息数。

文章:http://www.rabbitmq.com/queues.html

#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> const char* device_names[] = { "Chrome浏览器", "Word文档", "Excel表格", "音乐播放器", "视频播放器", "图片编辑器", "终端窗口", "文件管理器", "邮件客户端", "PDF阅读器", "代码编辑器", "系统监控器", "游戏程序", "下载管理器", "压缩工具", "虚拟机" }; typedef struct Process { int pid; char name[50]; int arrival_time; int burst_time; int remaining_time; int waiting_time; int turnaround_time; int completion_time; int queue_level; } Process; // 队列节点 typedef struct Node { Process *process; struct Node *next; } Node; // 队列结构 typedef struct Queue { Node *front; Node *rear; int time_quantum; int level; char priority[20]; } Queue; Process* createProcess(int pid, const char* name, int arrival_time, int burst_time) { Process *p = (Process*)malloc(sizeof(Process)); p->pid = pid; strcpy(p->name, name); p->arrival_time = arrival_time; p->burst_time = burst_time; p->remaining_time = burst_time; p->waiting_time = 0; p->turnaround_time = 0; p->completion_time = 0; p->queue_level = 0; return p; } Queue* createQueue(int time_quantum, int level, const char* priority) { Queue *q = (Queue*)malloc(sizeof(Queue)); q->front = q->rear = NULL; q->time_quantum = time_quantum; q->level = level; strcpy(q->priority, priority); return q; } bool isEmpty(Queue *q) { return q->front == NULL; } void enqueue(Queue *q, Process *p) { Node *newNode = (Node*)malloc(sizeof(Node)); newNode->process = p; newNode->next = NULL; if (isEmpty(q)) { q->front = q->rear = newNode; } else { q->rear->next = newNode; q->rear = newNode; } } Process* dequeue(Queue *q) { if (isEmpty(q)) { return NULL; } Node *temp = q->front; Process *p = temp->process; q->front = q->front->next; if (q->front == NULL) { q->rear = NULL; } free(temp); return p; } int getQueueSize(Queue *q) { int count = 0; Node *current = q->front; while (current != NULL) { count++; current = current->next; } return count; } const char* getPriorityDescription(int level, int total_queues) { if (total_queues == 1) return "唯一队列"; if (level == 0) return "最高优先级"; if (level == total_queues - 1) return "最低优先级"; if (level == 1) return "高优先级"; if (level == total_queues - 2) return "低优先级"; float position = (float)level / (total_queues - 1); if (position < 0.33) return "高优先级"; if (position < 0.67) return "中优先级"; return "低优先级"; } int displayWidth(const char* str) { int width = 0; while (*str) { if ((unsigned char)*str >= 0x80) { width += 2; str += 3; } else { width += 1; str += 1; } } return width; } void displayQueues(Queue **queues, int queue_count, int current_time) { printf("\n"); printf("+------------------------------------------------------------------------+\n"); printf("| 当前时间: %-4d |\n", current_time); printf("+--------+----------------+----------+-----------------------------------+\n"); printf("| 队列ID | 优先级描述 | 时间片 | 队列中的进程 |\n"); printf("+--------+----------------+----------+-----------------------------------+\n"); for (int i = 0; i < queue_count; i++) { printf("| %-4d | %-14s | %-8d | ", i, queues[i]->priority, queues[i]->time_quantum); if (isEmpty(queues[i])) { printf("%-33s |\n", "空队列"); } else { Node *current = queues[i]->front; char display_buffer[100] = ""; int count = 0; while (current != NULL && count < 3) { char temp[50]; if (count > 0) { sprintf(temp, ", %s", current->process->name); } else { sprintf(temp, "%s", current->process->name); } if (strlen(display_buffer) + strlen(temp) <= 30) { strcat(display_buffer, temp); count++; current = current->next; } else { break; } } if (current != NULL) { int remaining = getQueueSize(queues[i]) - count; char remaining_str[20]; sprintf(remaining_str, " ...(+%d)", remaining); if (strlen(display_buffer) + strlen(remaining_str) <= 33) { strcat(display_buffer, remaining_str); } } printf("%-33s |\n", display_buffer); } } printf("+--------+----------------+----------+-----------------------------------+\n"); } void displayProcessStatus(Process **processes, int n) { printf("\n进程状态表:\n"); printf("+-----+------------------+----------+----------+----------+----------+----------+\n"); printf("| PID | 进程名称 | 到达时间 | 执行时间 | 剩余时间 | 队列级别 | 状态 |\n"); printf("+-----+------------------+----------+----------+----------+----------+----------+\n"); for (int i = 0; i < n; i++) { char status[20]; if (processes[i]->remaining_time == 0) { strcpy(status, "已完成"); } else if (processes[i]->arrival_time > 0 && processes[i]->remaining_time == processes[i]->burst_time) { strcpy(status, "未到达"); } else if (processes[i]->remaining_time > 0) { strcpy(status, "就绪中"); } else { strcpy(status, "运行中"); } printf("| %-3d | %-16s | %-8d | %-8d | %-8d | %-8d | %-8s |\n", processes[i]->pid, processes[i]->name, processes[i]->arrival_time, processes[i]->burst_time, processes[i]->remaining_time, processes[i]->queue_level, status); } printf("+-----+------------------+----------+----------+----------+----------+----------+\n"); } bool isProcessInAnyQueue(Queue **queues, int queue_count, int pid) { for (int q = 0; q < queue_count; q++) { Node *current = queues[q]->front; while (current != NULL) { if (current->process->pid == pid) { return true; } current = current->next; } } return false; } // 多级反馈队列调度算法 void multilevelFeedbackQueueScheduling(Process **processes, int n, int queue_count, int *time_quantums) { Queue **queues = (Queue**)malloc(queue_count * sizeof(Queue*)); for (int i = 0; i < queue_count; i++) { queues[i] = createQueue(time_quantums[i], i, getPriorityDescription(i, queue_count)); } int current_time = 0; int completed = 0; int total_processes = n; printf("\n开始执行多级反馈队列调度...\n"); while (completed < total_processes) { // 先处理进程到达 - 确保新到达进程立即加入队列 for (int i = 0; i < n; i++) { if (processes[i]->arrival_time <= current_time && processes[i]->remaining_time > 0 && !isProcessInAnyQueue(queues, queue_count, processes[i]->pid)) { processes[i]->queue_level = 0; enqueue(queues[0], processes[i]); printf("\n[到达] 时间 %d: 进程 [%s] 到达系统,加入队列 %d (%s)\n", current_time, processes[i]->name, 0, queues[0]->priority); } } // 再显示当前状态 displayQueues(queues, queue_count, current_time); displayProcessStatus(processes, n); bool process_executed = false; for (int i = 0; i < queue_count; i++) { if (!isEmpty(queues[i])) { Process *current_process = dequeue(queues[i]); int time_quantum = queues[i]->time_quantum; int execution_time; if (current_process->remaining_time <= time_quantum) { execution_time = current_process->remaining_time; } else { execution_time = time_quantum; } printf("\n[执行] 时间 %d: 执行进程 [%s] (队列 %d: %s), 执行 %d 单位时间\n", current_time, current_process->name, i, queues[i]->priority, execution_time); // 在执行前先更新其他进程的等待时间 for (int j = 0; j < n; j++) { if (processes[j] != current_process && processes[j]->arrival_time <= current_time && processes[j]->remaining_time > 0 && processes[j]->completion_time == 0) { processes[j]->waiting_time += execution_time; } } current_process->remaining_time -= execution_time; current_time += execution_time; if (current_process->remaining_time == 0) { current_process->completion_time = current_time; current_process->turnaround_time = current_process->completion_time - current_process->arrival_time; completed++; printf("\n[完成] 时间 %d: 进程 [%s] 执行完成!\n", current_time, current_process->name); } else { if (i < queue_count - 1) { current_process->queue_level = i + 1; enqueue(queues[i + 1], current_process); printf("\n[降级] 时间 %d: 进程 [%s] 从队列 %d (%s) 降级到队列 %d (%s)\n", current_time, current_process->name, i, queues[i]->priority, i + 1, queues[i + 1]->priority); } else { enqueue(queues[i], current_process); printf("\n[重排] 时间 %d: 进程 [%s] 在队列 %d (%s) 中重新排队\n", current_time, current_process->name, i, queues[i]->priority); } } process_executed = true; break; } } if (!process_executed) { int next_arrival = current_time + 1; for (int i = 0; i < n; i++) { if (processes[i]->arrival_time > current_time && processes[i]->remaining_time > 0) { if (next_arrival == current_time + 1 || processes[i]->arrival_time < next_arrival) { next_arrival = processes[i]->arrival_time; } } } printf("\n[空闲] 时间 %d: CPU 空闲,跳到时间 %d\n", current_time, next_arrival); current_time = next_arrival; } printf("\n按回车键继续..."); getchar(); } int total_burst_time = 0; for (int i = 0; i < n; i++) { total_burst_time += processes[i]->burst_time; } printf("\n调度结果统计:\n"); printf("+-----+------------------+----------+----------+----------+----------+----------+\n"); printf("| PID | 进程名称 | 到达时间 | 执行时间 | 完成时间 | 周转时间 | 等待时间 |\n"); printf("+-----+------------------+----------+----------+----------+----------+----------+\n"); float total_turnaround = 0, total_waiting = 0; for (int i = 0; i < n; i++) { printf("| %-3d | %-16s | %-8d | %-8d | %-8d | %-8d | %-8d |\n", processes[i]->pid, processes[i]->name, processes[i]->arrival_time, processes[i]->burst_time, processes[i]->completion_time, processes[i]->turnaround_time, processes[i]->waiting_time); total_turnaround += processes[i]->turnaround_time; total_waiting += processes[i]->waiting_time; } printf("+-----+------------------+----------+----------+----------+----------+----------+\n"); printf("\n性能指标:\n"); printf("+--------------------------------+\n"); printf("| 平均周转时间: %-12.2f |\n", total_turnaround / n); printf("| 平均等待时间: %-12.2f |\n", total_waiting / n); printf("| CPU利用率: %-10.2f%% |\n", (current_time > 0 ? (total_burst_time * 100.0) / current_time : 0)); printf("+--------------------------------+\n"); for (int i = 0; i < queue_count; i++) { while (!isEmpty(queues[i])) { dequeue(queues[i]); } free(queues[i]); } free(queues); } void inputProcesses(Process ***processes, int *n) { printf("请输入进程数量: "); scanf("%d", n); getchar(); *processes = (Process**)malloc((*n) * sizeof(Process*)); printf("\n请依次输入每个进程的信息(进程ID 到达时间 执行时间):\n"); printf("可用设备类型: \n"); int device_count = sizeof(device_names) / sizeof(device_names[0]); for (int i = 0; i < device_count && i < 12; i++) { printf(" %2d. %s\n", i+1, device_names[i]); } for (int i = 0; i < *n; i++) { int pid, arrival_time, burst_time; printf("\n进程 %d (PID 到达时间 执行时间): ", i + 1); scanf("%d %d %d", &pid, &arrival_time, &burst_time); getchar(); int device_index = pid % (sizeof(device_names)/sizeof(device_names[0])); (*processes)[i] = createProcess(pid, device_names[device_index], arrival_time, burst_time); } } void inputQueueParameters(int *queue_count, int **time_quantums) { printf("\n请输入队列数量: "); scanf("%d", queue_count); getchar(); *time_quantums = (int*)malloc((*queue_count) * sizeof(int)); printf("\n请依次输入每个队列的时间片大小:\n"); for (int i = 0; i < *queue_count; i++) { printf("队列 %d 时间片: ", i); scanf("%d", &(*time_quantums)[i]); getchar(); } } int main() { Process **processes = NULL; int n = 0; int queue_count = 0; int *time_quantums = NULL; printf("================================================================================\n"); printf(" 多级反馈队列调度算法模拟器\n"); printf("================================================================================\n"); inputProcesses(&processes, &n); inputQueueParameters(&queue_count, &time_quantums); printf("\n输入信息汇总:\n"); printf("+-----+------------------+----------+----------+\n"); printf("| PID | 进程名称 | 到达时间 | 执行时间 |\n"); printf("+-----+------------------+----------+----------+\n"); for (int i = 0; i < n; i++) { printf("| %-3d | %-16s | %-8d | %-8d |\n", processes[i]->pid, processes[i]->name, processes[i]->arrival_time, processes[i]->burst_time); } printf("+-----+------------------+----------+----------+\n"); printf("\n队列信息:\n"); printf("+----------+------------+----------------+\n"); printf("| 队列级别 | 时间片大小 | 优先级描述 |\n"); printf("+----------+------------+----------------+\n"); for (int i = 0; i < queue_count; i++) { printf("| %-8d | %-10d | %-14s |\n", i, time_quantums[i], getPriorityDescription(i, queue_count)); } printf("+----------+------------+----------------+\n"); printf("\n模拟即将开始...\n"); multilevelFeedbackQueueScheduling(processes, n, queue_count, time_quantums); for (int i = 0; i < n; i++) { free(processes[i]); } free(processes); free(time_quantums); printf("\n模拟结束,感谢使用!\n"); return 0; }这段代码有什么问题,请帮我修改,UI界面不要修改
最新发布
11-27
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值