R语言simmer仿真中自定义动态weight队列优先级策略的实现问询
Absolutely! You can absolutely build a custom scheduling logic in simmer to handle this dynamic weight-based priority—this is one of the package's greatest strengths for flexible simulation workflows. Let me break down exactly how to implement it with code examples you can adapt for your use case.
Step 1: Store Task Attributes on Arrival
First, you need to capture each task's core attributes (base priority and arrival time) when it enters the simulation. These will be used to calculate the dynamic weight later.
library(simmer) # Define the task trajectory: capture base priority and arrival time task_trajectory <- trajectory() %>% # Assign a random base priority (adjust this to match your actual task data) set_attribute("base_priority", function() sample(1:5, 1)) %>% # Store the exact time the task arrives in the system set_attribute("arrival_time", function() now(env)) %>% # Seize the processing resource (priority logic is handled via custom selection) seize("processing_resource") %>% # Simulate processing time (adjust duration to match your task requirements) timeout(function() sample(3600:10800, 1)) %>% # 1-3 hours in seconds release("processing_resource")
Step 2: Define Custom Weight Calculation & Task Selection
Next, create a custom selection function that evaluates every task in the waiting list, computes its dynamic weight using your formula, and picks the task with the highest weight.
For example, we'll use a weight formula like:weight = base_priority + (waiting_days * 2)
(tweak the multiplier or formula to fit your specific business rules)
# Custom function to select the task with the highest dynamic weight select_highest_weight <- function(queue) { # Calculate weight for each task in the waiting queue task_weights <- sapply(queue, function(task) { # Extract stored task attributes base_prio <- task$attributes$base_priority arrival_time <- task$attributes$arrival_time # Convert waiting time from seconds to days waiting_days <- (now(task$env) - arrival_time) / 86400 # Compute dynamic weight per your logic base_prio + (waiting_days * 2) }) # Return the index of the task with the maximum weight which.max(task_weights) }
Step 3: Set Up the Simulation Environment
Create your simulation environment, attach the resource with your custom selection function, and add the task generator.
# Initialize simulation environment sim_env <- simmer() %>% # Add processing resource with custom selection logic add_resource( name = "processing_resource", capacity = 1, # Adjust to match your number of parallel processors queue_size = Inf, # Allow unlimited tasks in the waiting list select = select_highest_weight # Use our custom task picker ) %>% # Add task generator (adjust inter-arrival time to match your scenario) add_generator( name_prefix = "task", trajectory = task_trajectory, distribution = function() rexp(1, 1/86400) # ~1 task per day on average ) # Run the simulation for 7 days (adjust duration as needed) sim_env %>% run(until = 7 * 86400)
Optional: Add Preemption for Higher Weight Tasks
If you want to allow a waiting task with a newly increased weight to preempt a task currently being processed, add a custom preemption check function:
# Custom preemption logic: preempt if a waiting task has higher weight than the running one preempt_for_higher_weight <- function(running_task, waiting_queue) { # Calculate weight for the currently running task running_weight <- { base_prio <- running_task$attributes$base_priority arrival_time <- running_task$attributes$arrival_time waiting_days <- (now(running_task$env) - arrival_time) / 86400 base_prio + (waiting_days * 2) } # Calculate maximum weight in the waiting queue queue_weights <- sapply(waiting_queue, function(task) { base_prio <- task$attributes$base_priority arrival_time <- task$attributes$arrival_time waiting_days <- (now(task$env) - arrival_time) / 86400 base_prio + (waiting_days * 2) }) max_queue_weight <- max(queue_weights) # Return TRUE to preempt if the queue has a higher-weight task max_queue_weight > running_weight }
Update the resource definition to include preemption:
sim_env_with_preemption <- simmer() %>% add_resource( name = "processing_resource", capacity = 1, queue_size = Inf, select = select_highest_weight, preemptive = TRUE, # Enable preemption functionality preempt = preempt_for_higher_weight, # Use our custom preemption logic preempt_order = "priority" # Resume preempted tasks based on weight later ) %>% add_generator("task", task_trajectory, function() rexp(1, 1/86400)) sim_env_with_preemption %>% run(until = 7 * 86400)
Key Notes
- Adjust the Weight Formula: Modify the calculation in
select_highest_weightto match your exact business rules (e.g., exponential weight increase, different multipliers for priority levels). - Extend Attributes: You can add more task-specific attributes (like task type or complexity) to the trajectory and include them in your weight calculation if needed.
- Resource Capacity: Tweak the
capacityparameter inadd_resourceto match the number of parallel workers in your real-world scenario.
内容的提问来源于stack exchange,提问作者Roos

