0

I know I can get a day string in format yyyyMMdd with SimpleDateFormat, but it introduces some cost which take 2 seconds for 10 millions operations when I test in my machine

Of cause I can cache this value and schedule a timer in 00:00Am and update this date cache,but I hope I can get this value in a easy enough way which will not introduce a explicit cost however If I can

I will call this operation in 1 million tps.

Is there an easy and fast enough way to do this.

JaskeyLam
  • 15,405
  • 21
  • 114
  • 149
  • 2
    Why do you need this date string? – Tim Biegeleisen Jun 12 '18 at 03:36
  • 1
    Are you creating a new SimpleDateFormat for each format operation? Consider pooling instances or using a thread-safe equivalent like [`DateTimeFormatter`](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html) or [`FastDateFormat`](https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/time/FastDateFormat.html). – shmosel Jun 12 '18 at 03:42
  • SimpleDateFormat is expensive to init look at https://stackoverflow.com/questions/22098904/how-to-improve-performance-of-simpledateformat-wrapped-in-threadlocal – Yogesh_D Jun 12 '18 at 03:58
  • @TimBiegeleisen, I need to accumulate some numbers in memory with high tps and then persist them in redis , with ST_{DATANO} – JaskeyLam Jun 12 '18 at 05:12

1 Answers1

1

I have check it locally:

1M - ~2.5 sec:

10M - ~49 sec:

public static List<String> convert(Date[] dates) {
    List<String> res = new ArrayList<>(dates.length);

    for (Date date : dates)
        res.add(new SimpleDateFormat("YYYYMMdd", Locale.US).format(date));

    return res;
}

1M - ~1.1 sec:

10M - ~26 sec:

public static List<String> convert(Date[] dates) {
    List<String> res = new ArrayList<>(dates.length);
    DateFormat df = new SimpleDateFormat("YYYYMMdd", Locale.US);

    for (Date date : dates)
        res.add(df.format(date));

    return res;
}

1M - ~1 sec:

10M - ~15.5 sec:

public static List<String> convert3(Date[] dates) throws ExecutionException, InterruptedException {
    int size = 1000;
    ThreadLocal<SimpleDateFormat> df = ThreadLocal.withInitial(() -> new SimpleDateFormat("YYYYMMdd", Locale.US));
    ExecutorService pool = Executors.newFixedThreadPool(10);

    List<Future<List<String>>> futures = new ArrayList<>(dates.length);

    for (int i = 0; i < dates.length; i += size) {
        int ii = i;
        futures.add(pool.submit(() -> {
            List<String> res = new ArrayList<>(size);
            SimpleDateFormat sdf = df.get();

            for (int j = 0; j < size && ii + j < dates.length; j++)
                res.add(sdf.format(dates[ii + j]));

            return res;
        }));
    }

    List<String> res = new ArrayList<>(dates.length);

    for (Future<List<String>> future : futures)
        res.addAll(future.get());

    pool.shutdown();

    return res;
}

I need to accumulate some numbers in memory with high tps and then persist them in redis , with ST_{DATANO}

I am think about one more think. I don't know could it be precisely, but you could look at my idea. What about just take long time in millisecond, and remove all parts that you do not care about: time part. This is example:

final long msOneDay = TimeUnit.DAYS.toMillis(1);  // milliseconds in one day: 86400000
Date originalDate = new Date(); // e.g. Sat Jan 03 12:36:05 MSK 1987
long dayId = originalDate .getTime() / msOneDay;  // 6211, this value you can store in Redis
Date restoredDate = new Date(dayId * msOneDay); // Sat Jan 03 03:00:00 MSK 1987 - correct date without time information

1M - ~1 sec:

10M - ~10.6 sec:

public static List<String> convert(Date[] dates) {
    List<String> res = new ArrayList<>(dates.length);
    long msOneDay = TimeUnit.DAYS.toMillis(1);

    for (Date date : dates)
        res.add(String.valueOf(date.getTime() / msOneDay));

    return res;
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35