java - 为批量任务实现通用进度跟踪器

标签 java background-process generic-programming

我目前正在开发一个项目,该项目有许多要执行的后台任务。每个任务创建后发送到一个并发服务,该服务管理所有任务的执行过程。每个任务在执行期间都存储在数据库表中。

我的困境是,每个任务都执行非常具体的功能,并且通常大多数委托(delegate)给系统另一部分中的服务,完成主要工作,然后任务返回。

目前,我实现了一个非常简单的系统,用于跟踪任务的进度,它运行良好,但是执行的每个任务都需要添加大量额外的代码来适应其委托(delegate)的服务的功能。

举个例子,我的任务有一个方法:

@Override
public void execute() {
    service.calculateAverage();
}

然后在服务中进行相应的操作:

public float calculateAverage() {
    float total = 0.0f; 
    for (i = 0; i < 20; i++) {
        total += i;
    }
    return total / 20;
}

跟踪进度相当简单,我只是在任务超过一定的迭代阈值后更新数据库中的任务。然而,事实证明,要概括这一点是一项艰巨的任务,因为执行的每个任务可能完全委托(delegate)给不同的服务。这意味着在每个服务中我需要添加特定于该服务的实现的代码。

我做了一些搜索,但似乎找不到任何好的模式可以帮助创建一个通用系统来跟踪每个任务的进度。任何指针,甚至只是查找或阅读的地方都会很好。

最佳答案

如果您让服务使用您自己的Iterator,而不是让它创建循环。

class SumService {

    private float calculateSum(Iterable<Integer> i) {
        float total = 0.0f;
        for (Integer x : i) {
            total += x;
        }
        return total;
    }

}

然后,您可以创建一个 Iterable 来跟踪进度并将其报告给进度跟踪器。

/**
 * State of progress - returns a double result between 0 and 1.
 *
 * Will be called repeatedly by the progress tracker.
 */
interface Progress {

    public double getProgress();
}

/**
 * The progress tracker.
 */
static class ProgressTracker {

    // All processes are registered.
    static void registerProgressor(Progress p) {
        // Add it to mmy list of people to watch.
    }
}

/**
 * An Iterable that reports its progress.
 */
class ProgressingIterable<T> implements Iterable<T>, Progress {

    // The iterable we are hosting.
    final Iterable<T> it;
    // How far we are to go.
    final int steps;
    // Where we're at now.
    volatile int at = 0;

    public ProgressingIterable(Iterable<T> it, int steps) {
        this.it = it;
        this.steps = steps;
    }

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            // Grab an Iterator from the Iterable.
            Iterator<T> i = it.iterator();

            @Override
            public boolean hasNext() {
                // Delegate.
                return i.hasNext();
            }

            @Override
            public T next() {
                // Keep track of the steps.
                at++;
                return i.next();
            }

        };
    }

    @Override
    public double getProgress() {
        // How are we doing?
        return (double) at / (double) steps;
    }

}

/**
 * A range (from http://stackoverflow.com/a/6828887/823393).
 *
 * @param begin inclusive
 * @param end exclusive
 * @return list of integers from begin to end
 */
public static List<Integer> range(final int begin, final int end) {
    return new AbstractList<Integer>() {
        @Override
        public Integer get(int index) {
            return begin + index;
        }

        @Override
        public int size() {
            return end - begin;
        }
    };
}

/**
 * A process.
 */
class Process {

    ProgressingIterable<Integer> progress = new ProgressingIterable<>(range(0, 20), 20);

    public void execute() {
        // Register the Progress
        ProgressTracker.registerProgressor(progress);
        // Make the service use my progress object.
        service.calculateSum(progress);
    }

}

// The service it uses.
SumService service = new SumService();

这可以管理职责的分离。对于服务来说,它只是一个Iterable,而对于进度跟踪器来说,它会在收到请求时提供当前进度。

我称之为Janus模式,因为你有一个对象恰好做两件事。它允许您将两个进程绑定(bind)到一个对象中。

我选择了最简单的进度指示器 - 01 之间的double。我相信你可以做得更好。

关于java - 为批量任务实现通用进度跟踪器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31590458/

相关文章:

java - 异步流上的多个操作

ios - geofence didEnterRegion/didExitRegion通知后如何进行BG NW下载

c - 多个结构,需要在方法中访问的相同字段

c++ - 如何使用带有模板参数和参数包的 enable if?

java - 我可以用 Java 在邮件服务器上执行搜索吗?

java - Spring 启动 (2.0.4.RELEASE) - IllegalArgumentException : Not a managed type

java - 用另一种颜色显示 System.out.println 输出

macos - netsession_mac 使用大量 CPU。它是什么?

java - JobRunr 调度java后台作业时出现异常

rust - 在 Rust 中为什么需要类型注释,即使它们在通用特征中明确指定