Вы можете использовать этот метод 1, который использует ClassLoader
.
/**
* Scans all classes accessible from the context class loader which belong to the given package and subpackages.
*
* @param packageName The base package
* @return The classes
* @throws ClassNotFoundException
* @throws IOException
*/
private static Class[] getClasses(String packageName)
throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration resources = classLoader.getResources(path);
List dirs = new ArrayList();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList classes = new ArrayList();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes.toArray(new Class[classes.size()]);
}
/**
* Recursive method used to find all classes in a given directory and subdirs.
*
* @param directory The base directory
* @param packageName The package name for classes found inside the base directory
* @return The classes
* @throws ClassNotFoundException
*/
private static List findClasses(File directory, String packageName) throws ClassNotFoundException {
List classes = new ArrayList();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}
__________ 1 Этот метод был взят из http: // фрагментов. dzone.com/posts/show/4831, который был архивирован через Интернет-архив, связанный с ним сейчас. Фрагмент также доступен в https://dzone.com/articles/get-all-classes-within-package .
Я пришел на вечеринку довольно поздно, но не вижу в ответах списка моих любимых трюков.
В * NIX аварийный сигнал (2)
наследуется через execve (2)
, а SIGALRM по умолчанию является критическим. Так что часто вы можете просто:
$ doalarm () { perl -e 'alarm shift; exec @ARGV' "$@"; } # define a helper function
$ doalarm 300 ./foo.sh args
или установить тривиальную оболочку C , чтобы сделать это за вас.
Преимущества Используется только один PID, и механизм прост. Вы не уничтожите не тот процесс, если, например, ./ foo.sh
завершился «слишком быстро» и его PID был повторно использован. Вам не нужно, чтобы несколько подпроцессов оболочки работали согласованно, что может быть выполнено правильно, но довольно чревато гонками.
Недостатки Ограниченный по времени процесс не может управлять своим будильником (например, alarm (2)
, ualarm (2)
, setitimer (2)
), так как это, скорее всего, сбросит унаследованный сигнал тревоги. Очевидно, он также не может блокировать или игнорировать SIGALRM, хотя то же самое можно сказать о SIGINT, SIGTERM и т. Д. Для некоторых других подходов.
Некоторые (как мне кажется, очень старые) системы реализуют sleep (2)
в терминах alarm (2)
, и даже сегодня некоторые программисты используют alarm ( 2)
как грубый внутренний механизм тайм-аута для ввода-вывода и других операций. Однако по моему опыту, этот метод применим к подавляющему большинству процессов, которые вы хотите ограничить по времени.
Небольшая модификация однострочника perl вернет статус выхода.
perl -e '$s = shift; $SIG{ALRM} = sub { print STDERR "Timeout!\n"; kill INT => $p; exit 77 }; exec(@ARGV) unless $p = fork; alarm $s; waitpid $p, 0; exit ($? >> 8)' 10 yes foo
Обычно exit ($? >> 8) пересылает статус выхода подпроцесса. Я просто выбрал 77 в статусе выхода для тайм-аута.
Попробуйте что-нибудь вроде:
# This function is called with a timeout (in seconds) and a pid.
# After the timeout expires, if the process still exists, it attempts
# to kill it.
function timeout() {
sleep $1
# kill -0 tests whether the process exists
if kill -0 $2 > /dev/null 2>&1 ; then
echo "killing process $2"
kill $2 > /dev/null 2>&1
else
echo "process $2 already completed"
fi
}
<your command> &
cpid=$!
timeout 3 $cpid
wait $cpid > /dev/null 2>&
exit $?
У этого есть обратная сторона: если pid вашего процесса повторно используется в течение тайм-аута, это может убить не тот процесс. Это маловероятно, но вы можете запускать более 20000 процессов в секунду. Это можно исправить.
Как насчет использования инструмента ожидания?
## run a command, aborting if timeout exceeded, e.g. timed-run 20 CMD ARGS ...
timed-run() {
# timeout in seconds
local tmout="$1"
shift
env CMD_TIMEOUT="$tmout" expect -f - "$@" <<"EOF"
# expect script follows
eval spawn -noecho $argv
set timeout $env(CMD_TIMEOUT)
expect {
timeout {
send_error "error: operation timed out\n"
exit 1
}
eof
}
EOF
}
чистый bash:
#!/bin/bash
if [[ $# < 2 ]]; then
echo "Usage: $0 timeout cmd [options]"
exit 1
fi
TIMEOUT="$1"
shift
BOSSPID=$$
(
sleep $TIMEOUT
kill -9 -$BOSSPID
)&
TIMERPID=$!
trap "kill -9 $TIMERPID" EXIT
eval "$@"
Я использую "timelimit", это пакет, доступный в репозитории debian.
Perl один лайнер, только для ударов:
perl -e '$s = shift; $SIG{ALRM} = sub { print STDERR "Timeout!\n"; kill INT => $p }; exec(@ARGV) unless $p = fork; alarm $s; waitpid $p, 0' 10 yes foo
Это печатает 'нечто' в течение десяти секунд, затем испытывает таймаут. Замените '10' любым числом секунд, и 'да нечто' с любой командой.
Существует также ulimit, который может использоваться для ограничения времени выполнения, доступного подпроцессам.
ulimit -t 10
Пределы процесс к 10 секундам процессорного времени.
Для фактического использования его для ограничения нового процесса, а не текущего процесса можно хотеть использовать сценарий обертки:
#! /usr/bin/env python
import os
os.system("ulimit -t 10; other-command-here")
другая-команда может быть любым инструментом. Я выполнял Java, Python, C и версии Схемы различных алгоритмов сортировки и вход, сколько времени они взяли при ограничении времени выполнения 30 секундами. Приложение Python какао генерировало различные командные строки - включая аргументы - и сопоставило времена в файл CSV, но это был действительно просто пух сверх команды, обеспеченной выше.
Возможно, я не понимаю вопроса, но это звучит выполнимым непосредственно, по крайней мере, в ударе:
( /path/to/slow command with options ) & sleep 5 ; kill $!
Это выполняет первую команду, в круглой скобке, в течение пяти секунд, и затем уничтожает ее. Вся операция работает синхронно, т.е. Вы не будете в состоянии использовать свою оболочку, в то время как это - активное ожидание медленной команды. Если это не то, что Вы хотели, должно быть возможно добавить другой &.
$!
переменная является Bash, встроенным, который содержит идентификатор процесса последний раз запущенной подоболочки. Важно не иметь & в круглой скобке делая его тот путь теряет идентификатор процесса.
У меня есть программа, названная timeout
, который делает это - записанный в C, первоначально в 1989, но обновляемый периодически с тех пор.
<час> Обновление: этому коду не удается скомпилировать на MacOS X, потому что SIGRTMIN не определяется и перестал работать к тайм-ауту при выполнении на MacOS X, потому что эти
signal()
функция там возобновляется wait()
после времен аварийного сигнала - который не является необходимым поведением. У меня есть новая версия timeout.c
, который имеет дело с обеими этими проблемами (использующий sigaction()
вместо signal()
). Как прежде, свяжитесь со мной для 10K gzipped файл tar с исходным кодом и страницей руководства (см. мой профиль). <час> /*
@(#)File: $RCSfile: timeout.c,v $
@(#)Version: $Revision: 4.6 $
@(#)Last changed: $Date: 2007/03/01 22:23:02 $
@(#)Purpose: Run command with timeout monitor
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 1989,1997,2003,2005-07
*/
#define _POSIX_SOURCE /* Enable kill() in <unistd.h> on Solaris 7 */
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "stderr.h"
#define CHILD 0
#define FORKFAIL -1
static const char usestr[] = "[-vV] -t time [-s signal] cmd [arg ...]";
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_timeout_c[] = "@(#)$Id: timeout.c,v 4.6 2007/03/01 22:23:02 jleffler Exp $";
#endif /* lint */
static void catcher(int signum)
{
return;
}
int main(int argc, char **argv)
{
pid_t pid;
int tm_out;
int kill_signal;
pid_t corpse;
int status;
int opt;
int vflag = 0;
err_setarg0(argv[0]);
opterr = 0;
tm_out = 0;
kill_signal = SIGTERM;
while ((opt = getopt(argc, argv, "vVt:s:")) != -1)
{
switch(opt)
{
case 'V':
err_version("TIMEOUT", &"@(#)$Revision: 4.6 $ ($Date: 2007/03/01 22:23:02 $)"[4]);
break;
case 's':
kill_signal = atoi(optarg);
if (kill_signal <= 0 || kill_signal >= SIGRTMIN)
err_error("signal number must be between 1 and %d\n", SIGRTMIN - 1);
break;
case 't':
tm_out = atoi(optarg);
if (tm_out <= 0)
err_error("time must be greater than zero (%s)\n", optarg);
break;
case 'v':
vflag = 1;
break;
default:
err_usage(usestr);
break;
}
}
if (optind >= argc || tm_out == 0)
err_usage(usestr);
if ((pid = fork()) == FORKFAIL)
err_syserr("failed to fork\n");
else if (pid == CHILD)
{
execvp(argv[optind], &argv[optind]);
err_syserr("failed to exec command %s\n", argv[optind]);
}
/* Must be parent -- wait for child to die */
if (vflag)
err_remark("time %d, signal %d, child PID %u\n", tm_out, kill_signal, (unsigned)pid);
signal(SIGALRM, catcher);
alarm((unsigned int)tm_out);
while ((corpse = wait(&status)) != pid && errno != ECHILD)
{
if (errno == EINTR)
{
/* Timed out -- kill child */
if (vflag)
err_remark("timed out - send signal %d to process %d\n", (int)kill_signal, (int)pid);
if (kill(pid, kill_signal) != 0)
err_syserr("sending signal %d to PID %d - ", kill_signal, pid);
corpse = wait(&status);
break;
}
}
alarm(0);
if (vflag)
{
if (corpse == (pid_t) -1)
err_syserr("no valid PID from waiting - ");
else
err_remark("child PID %u status 0x%04X\n", (unsigned)corpse, (unsigned)status);
}
if (corpse != pid)
status = 2; /* Dunno what happened! */
else if (WIFEXITED(status))
status = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
status = WTERMSIG(status);
else
status = 2; /* Dunno what happened! */
return(status);
}
, Если Вы хотите 'официальный' код для 'stderr.h' и 'stderr.c', свяжитесь со мной (см. мой профиль).