Skip to content

Commit 3250e64

Browse files
committed
IO sync spike
1 parent 3f687fc commit 3250e64

File tree

6 files changed

+415
-0
lines changed

6 files changed

+415
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea/*
2+
target/*
3+
*.iml
4+
.java-version
5+
.DS_Store

pom.xml

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>com.jnape.palatable</groupId>
7+
<artifactId>parent</artifactId>
8+
<version>1.0</version>
9+
</parent>
10+
11+
<artifactId>lambda-io</artifactId>
12+
<version>1.0-SNAPSHOT</version>
13+
<packaging>jar</packaging>
14+
15+
<name>Lambda</name>
16+
<description>
17+
An IO monad for Java built on top of lambda.
18+
</description>
19+
20+
<url>http://www.github.com/palatable/lambda-io</url>
21+
22+
<licenses>
23+
<license>
24+
<name>The MIT License (MIT)</name>
25+
<url>http://choosealicense.com/licenses/mit</url>
26+
<distribution>repo</distribution>
27+
</license>
28+
</licenses>
29+
30+
<scm>
31+
<connection>scm:git:[email protected]:palatable/lambda-io.git</connection>
32+
<developerConnection>scm:git:[email protected]:palatable/lambda-io.git</developerConnection>
33+
<url>[email protected]:palatable/lambda-io.git</url>
34+
</scm>
35+
36+
<distributionManagement>
37+
<snapshotRepository>
38+
<id>ossrh</id>
39+
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
40+
</snapshotRepository>
41+
<repository>
42+
<id>ossrh</id>
43+
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
44+
</repository>
45+
</distributionManagement>
46+
47+
<developers>
48+
<developer>
49+
<id>jnape</id>
50+
<name>John Napier</name>
51+
<email>[email protected]</email>
52+
</developer>
53+
</developers>
54+
55+
<properties>
56+
<traitor.version>1.3.0</traitor.version>
57+
<maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>
58+
<hamcrest.version>2.1</hamcrest.version>
59+
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
60+
</properties>
61+
62+
<dependencies>
63+
<dependency>
64+
<groupId>junit</groupId>
65+
<artifactId>junit</artifactId>
66+
</dependency>
67+
<dependency>
68+
<groupId>com.jnape.palatable</groupId>
69+
<artifactId>lambda</artifactId>
70+
<version>5.3.0</version>
71+
</dependency>
72+
<dependency>
73+
<groupId>org.hamcrest</groupId>
74+
<artifactId>hamcrest</artifactId>
75+
<version>${hamcrest.version}</version>
76+
<scope>test</scope>
77+
</dependency>
78+
<dependency>
79+
<groupId>org.mockito</groupId>
80+
<artifactId>mockito-core</artifactId>
81+
<version>2.28.2</version>
82+
<scope>test</scope>
83+
</dependency>
84+
<dependency>
85+
<groupId>com.jnape.palatable</groupId>
86+
<artifactId>traitor</artifactId>
87+
<version>${traitor.version}</version>
88+
<scope>test</scope>
89+
</dependency>
90+
</dependencies>
91+
92+
<build>
93+
<plugins>
94+
<plugin>
95+
<groupId>org.apache.maven.plugins</groupId>
96+
<artifactId>maven-compiler-plugin</artifactId>
97+
<version>${maven-compiler-plugin.version}</version>
98+
<configuration>
99+
<source>1.8</source>
100+
<target>1.8</target>
101+
<compilerArgs>
102+
<compilerArg>-Xlint:all</compilerArg>
103+
<compilerArg>-Werror</compilerArg>
104+
</compilerArgs>
105+
</configuration>
106+
</plugin>
107+
<plugin>
108+
<groupId>org.apache.maven.plugins</groupId>
109+
<artifactId>maven-jar-plugin</artifactId>
110+
<version>${maven-jar-plugin.version}</version>
111+
<executions>
112+
<execution>
113+
<goals>
114+
<goal>test-jar</goal>
115+
</goals>
116+
</execution>
117+
</executions>
118+
</plugin>
119+
</plugins>
120+
</build>
121+
122+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.jnape.palatable.lambda.benchmark;
2+
3+
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
4+
import com.jnape.palatable.lambda.functions.Fn1;
5+
import com.jnape.palatable.lambda.newIO.IO;
6+
import com.jnape.palatable.lambda.semigroup.Semigroup;
7+
8+
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
9+
import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times;
10+
import static com.jnape.palatable.lambda.newIO.IO.io;
11+
import static com.jnape.palatable.lambda.semigroup.builtin.Collapse.collapse;
12+
13+
public final class FlatMap {
14+
private FlatMap() {
15+
}
16+
17+
public static void main(String[] args) {
18+
int samples = 10_000_000;
19+
System.out.println("Samples: " + samples);
20+
21+
Tuple2<Long, Long> oldTimings = benchmark(
22+
"Sync: Old FlatMap",
23+
com.jnape.palatable.lambda.io.IO.io(() -> 0),
24+
io -> io.flatMap(x -> com.jnape.palatable.lambda.io.IO.io(() -> x + 1)),
25+
com.jnape.palatable.lambda.io.IO::unsafePerformIO,
26+
samples);
27+
Tuple2<Long, Long> newTimings = benchmark(
28+
"Sync: New FlatMap",
29+
io(() -> 0),
30+
io -> io.then(x -> io(() -> x + 1)),
31+
IO::unsafePerformIO,
32+
samples);
33+
34+
printComparison(oldTimings, newTimings);
35+
}
36+
37+
private static void printComparison(Tuple2<Long, Long> oldTimings, Tuple2<Long, Long> newTimings) {
38+
Semigroup<Long> compareOldAndNew = (oldM, newM) -> (newM / oldM) * 100;
39+
Tuple2<Long, Long> percentDiff = collapse(compareOldAndNew, compareOldAndNew, oldTimings, newTimings);
40+
41+
System.out.println("Build new-vs-old: " + percentDiff._1() + "%");
42+
System.out.println("Run new-vs-old: " + percentDiff._2() + "%");
43+
}
44+
45+
public static <IO> Tuple2<Long, Long> benchmark(String label, IO io, Fn1<IO, IO> build, Fn1<IO, Object> run,
46+
int samples) {
47+
System.gc();
48+
System.out.println("=== " + label + " ===");
49+
System.out.print("Building...");
50+
long startBuildMs = System.currentTimeMillis();
51+
IO built = times(samples, build, io);
52+
long totalBuildMs = System.currentTimeMillis() - startBuildMs;
53+
System.out.print("built (" + (samples / totalBuildMs) + " ops/ms). Running...");
54+
long startRunMs = System.currentTimeMillis();
55+
Object result = run.apply(built);
56+
long totalRunMs = System.currentTimeMillis() - startRunMs;
57+
System.out.println("finished: " + result + " (" + (samples / totalRunMs) + " ops/ms).");
58+
return tuple(samples / totalBuildMs, samples / totalRunMs);
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.jnape.palatable.lambda.newIO;
2+
3+
import com.jnape.palatable.lambda.adt.Unit;
4+
import com.jnape.palatable.lambda.functions.Fn0;
5+
import com.jnape.palatable.lambda.functions.Fn1;
6+
import com.jnape.palatable.lambda.functions.specialized.SideEffect;
7+
8+
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
9+
import static com.jnape.palatable.lambda.newIO.UnsafeRunSync.unsafeRunSync;
10+
11+
public abstract class IO<A> {
12+
13+
private IO() {
14+
}
15+
16+
public abstract <R> R interpret(Interpreter<A, R> interpreter);
17+
18+
public final <B> IO<B> then(Fn1<? super A, ? extends IO<B>> f) {
19+
return new Sequential<>(this, f);
20+
}
21+
22+
public final <B> IO<B> fork(IO<Fn1<? super A, ? extends B>> ioF) {
23+
return new Parallel<>(this, ioF);
24+
}
25+
26+
public static <A> IO<A> io(A a) {
27+
return new Value<>(a);
28+
}
29+
30+
public static <A> IO<A> io(Fn0<A> thunk) {
31+
return new Suspension<>(thunk);
32+
}
33+
34+
public static IO<Unit> io(SideEffect sideEffect) {
35+
return io(() -> {
36+
sideEffect.Ω();
37+
return UNIT;
38+
});
39+
}
40+
41+
public final A unsafePerformIO() {
42+
return interpret(unsafeRunSync());
43+
}
44+
45+
private static final class Value<A> extends IO<A> {
46+
private final A a;
47+
48+
private Value(A a) {
49+
this.a = a;
50+
}
51+
52+
@Override
53+
public <R> R interpret(Interpreter<A, R> interpreter) {
54+
return interpreter.run(a);
55+
}
56+
}
57+
58+
private static final class Suspension<A> extends IO<A> {
59+
private final Fn0<A> thunk;
60+
61+
private Suspension(Fn0<A> thunk) {
62+
this.thunk = thunk;
63+
}
64+
65+
@Override
66+
public <R> R interpret(Interpreter<A, R> interpreter) {
67+
return interpreter.run(thunk);
68+
}
69+
}
70+
71+
private static final class Parallel<Z, A> extends IO<A> {
72+
private final IO<Z> ioZ;
73+
private final IO<Fn1<? super Z, ? extends A>> ioF;
74+
75+
private Parallel(IO<Z> ioZ, IO<Fn1<? super Z, ? extends A>> ioF) {
76+
this.ioZ = ioZ;
77+
this.ioF = ioF;
78+
}
79+
80+
@Override
81+
public <R> R interpret(Interpreter<A, R> interpreter) {
82+
return interpreter.run(ioZ, ioF);
83+
}
84+
}
85+
86+
private static final class Sequential<Z, A> extends IO<A> {
87+
private final IO<Z> ioZ;
88+
private final Fn1<? super Z, ? extends IO<A>> f;
89+
90+
private Sequential(IO<Z> ioZ, Fn1<? super Z, ? extends IO<A>> f) {
91+
this.ioZ = ioZ;
92+
this.f = f;
93+
}
94+
95+
@Override
96+
public <R> R interpret(Interpreter<A, R> interpreter) {
97+
return interpreter.run(ioZ, f);
98+
}
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.jnape.palatable.lambda.newIO;
2+
3+
import com.jnape.palatable.lambda.functions.Fn0;
4+
import com.jnape.palatable.lambda.functions.Fn1;
5+
6+
public interface Interpreter<A, R> {
7+
8+
R run(A a);
9+
10+
R run(Fn0<A> thunk);
11+
12+
<Z> R run(com.jnape.palatable.lambda.newIO.IO<Z> ioZ, com.jnape.palatable.lambda.newIO.IO<Fn1<? super Z, ? extends A>> ioF);
13+
14+
<Z> R run(com.jnape.palatable.lambda.newIO.IO<Z> ioZ, Fn1<? super Z, ? extends IO<A>> f);
15+
16+
17+
}

0 commit comments

Comments
 (0)