Hone logo
Hone
Problems

Asynchronous Task Queue in Python

Building a task queue is a fundamental pattern in distributed systems and asynchronous programming. This challenge asks you to implement a simplified task queue in Python, allowing you to defer the execution of functions to be processed later, improving application responsiveness and scalability. This is useful for handling long-running operations like sending emails, processing images, or making API calls without blocking the main thread.

Problem Description

You are to implement a TaskQueue class in Python. This class should manage a queue of tasks, where each task is a function to be executed along with its arguments. The queue should support adding tasks, processing tasks, and checking the queue's status.

Key Requirements:

  • add_task(func, *args, **kwargs): Adds a task to the queue. The task is represented by a function func and its positional and keyword arguments *args and **kwargs.
  • process_task(): Removes and executes the next task from the queue. If the queue is empty, it should return None.
  • is_empty(): Returns True if the queue is empty, False otherwise.
  • size(): Returns the number of tasks currently in the queue.

Expected Behavior:

The add_task method should enqueue the task (function and arguments) for later execution. The process_task method should dequeue the next task, call the function with the provided arguments, and return the result of the function call. The is_empty and size methods should accurately reflect the queue's state.

Edge Cases to Consider:

  • Empty queue when process_task() is called.
  • Tasks that raise exceptions during execution. The process_task method should not crash the entire queue; it should handle exceptions gracefully (e.g., by logging the error and returning None).
  • Functions with no arguments.
  • Functions with only keyword arguments.
  • Functions with both positional and keyword arguments.

Examples

Example 1:

Input:
queue = TaskQueue()
queue.add_task(lambda x: x * 2, 5)
result = queue.process_task()

Output:
10
Explanation: The lambda function `lambda x: x * 2` is added to the queue with the argument 5. `process_task()` dequeues the function, calls it with 5, and returns the result (10).

Example 2:

Input:
queue = TaskQueue()
queue.add_task(lambda x, y=10: x + y, 3, y=5)
result = queue.process_task()

Output:
8
Explanation: The lambda function `lambda x, y=10: x + y` is added to the queue with the argument 3 and keyword argument y=5. `process_task()` dequeues the function, calls it with 3 and y=5, and returns the result (8).

Example 3: (Edge Case - Empty Queue)

Input:
queue = TaskQueue()
result = queue.process_task()

Output:
None
Explanation: The queue is empty. `process_task()` returns None.

Constraints

  • The queue should be implemented using a standard Python data structure (e.g., list, collections.deque).
  • The functions added to the queue can be any callable object (functions, lambdas, methods).
  • The process_task method should handle exceptions raised by the executed functions without crashing the queue. Logging the exception is recommended but not strictly required.
  • The time complexity of add_task should be O(1).
  • The time complexity of process_task should be O(1).
  • The time complexity of is_empty should be O(1).
  • The time complexity of size should be O(1).

Notes

Consider using a deque from the collections module for efficient queue operations. Think about how to handle exceptions gracefully within the process_task method to prevent the entire queue from failing if a task encounters an error. The focus is on the core queue functionality; error handling and advanced features like prioritization or concurrency are not required for this challenge.

Loading editor...
python