Skip to content

Instantly share code, notes, and snippets.

@jeswr
Created March 24, 2022 02:54
Show Gist options
  • Save jeswr/e17029d06a5cf25ce2c59eae4196a5a5 to your computer and use it in GitHub Desktop.
Save jeswr/e17029d06a5cf25ce2c59eae4196a5a5 to your computer and use it in GitHub Desktop.
AsyncIterator performance tests
import { CLOSED, ENDED } from 'asynciterator';
import { ArrayIterator as OldArrayIterator } from 'asynciterator';
import { ArrayIterator, AsyncIterator, range } from './asynciterator'
type Transform = {
type: 'filter';
function: (elem: any) => boolean
} | {
type: 'map';
function: (elem: any) => any
}
function build(tranforms: Transform[]) {
const rev = tranforms.reverse();
return rev.slice(1, tranforms.length).reduce((f, transform) => {
return transform.type === 'map' ?
(item: any) => transform.function(f(item)) :
(item: any) => transform.function(item) ? f(item) : null;
}, rev[0].function);
}
class CompositeMapFilterVeryVeryFast<T> extends AsyncIterator<T> {
private tranforms: Transform[] = [];
private f: any;
constructor(private source: AsyncIterator<T>) {
super();
source.on('readable', () => {
this.emit('readable');
});
}
read(): T | null {
const { f, source } = this
let item = source.read();
while ((item = source.read()) !== null) {
item = (f as any)(item);
if (item !== null)
return item;
}
// @ts-ignore
if (source._state === ENDED) {
this._end();
}
return item;
}
// @ts-ignore
filter(filter: (item: T) => boolean, self?: any): CompositeMapFilterVeryVeryFast<T> {
this.tranforms.push({ type: 'filter', function: filter });
return this;
}
// @ts-ignore
map(map: (item: T) => T): CompositeMapFilterVeryVeryFast<T> {
this.tranforms.push({ type: 'map', function: map });
return this;
}
build() {
this.f = build(this.tranforms);
}
}
class CompositeMapFilterVeryFast<T> extends AsyncIterator<T> {
private tranforms: Transform[] = [];
private f: any;
constructor(private source: AsyncIterator<T>) {
super();
source.on('readable', () => {
this.emit('readable');
});
}
read(): T | null {
let item;
while ((item = this.source.read()) !== null) {
item = (this.f as any)(item);
if (item !== null)
return item;
}
// @ts-ignore
if (item === null && this.source._state === ENDED) {
this._end();
}
return item;
}
// @ts-ignore
filter(filter: (item: T) => boolean, self?: any): CompositeMapFilterVeryFast<T> {
this.tranforms.push({ type: 'filter', function: filter });
return this;
}
// @ts-ignore
map(map: (item: T) => T): CompositeMapFilterVeryFast<T> {
this.tranforms.push({ type: 'map', function: map });
return this;
}
build() {
this.f = build(this.tranforms);
}
}
class CompositeMapFilterFast<T> extends AsyncIterator<T> {
private tranforms?: Function;
constructor(private source: AsyncIterator<T>) {
super();
source.on('readable', () => {
this.emit('readable');
});
}
read(): T | null {
let item;
while ((item = this.source.read()) !== null) {
item = (this.tranforms as any)(item);
if (item !== null)
return item;
}
// @ts-ignore
if (item === null && this.source._state === ENDED) {
this._end();
}
return item;
}
// @ts-ignore
filter(filter: (item: T) => boolean, self?: any): CompositeMapFilterFast<T> {
if (!this.tranforms) {
this.tranforms = (item: any) => item !== null && filter(item) ? item : null;
} else {
const { tranforms } = this
this.tranforms = (item: any) => {
const transform = (tranforms as any)(item);
return transform !== null && filter(transform) ? transform : null;
}
}
return this;
}
// @ts-ignore
map(map: (item: T) => T): CompositeMapFilterFast<T> {
if (!this.tranforms) {
this.tranforms = (item: any) => item !== null ? map(item) : null
} else {
const { tranforms } = this
this.tranforms = (item: any) => {
const transform = (tranforms as any)(item);
return transform !== null ? map(transform) : null;
}
}
return this;
}
}
class CompositeMapFilter<T> extends AsyncIterator<T> {
private tranforms: Transform[] = [];
constructor(private source: AsyncIterator<T>) {
super();
source.on('readable', () => {
this.emit('readable');
});
}
read(): T | null {
let item = this.source.read();
for (let i = 0; i < this.tranforms.length; i += 1) {
const transform = this.tranforms[i];
switch (transform.type) {
case 'map':
item = transform.function(item);
case 'filter': {
if (!transform.function(item)) {
if ((item = this.source.read()) === null)
break;
else
i = 0
}
}
}
}
// @ts-ignore
if (item === null && this.source._state === ENDED) {
this._end();
}
return item;
}
// @ts-ignore
filter(filter: (item: T) => boolean, self?: any): CompositeMapFilter<T> {
this.tranforms.push({ type: 'filter', function: filter });
return this;
}
// @ts-ignore
map(map: (item: T) => T): CompositeMapFilter<T> {
this.tranforms.push({ type: 'map', function: map });
return this;
}
}
class MappingIterator<I, O> extends AsyncIterator<O> {
constructor(source: AsyncIterator<I>, map: (item: I) => O) {
super();
source.on('readable', () => {
this.emit('readable');
});
let item: I | null;
this.read = (): O | null => {
const item = source.read();
if (item === null) {
// @ts-ignore
if (source._state === ENDED || source._state === CLOSED)
this._end();
return null
}
return map(item);
};
}
}
class FilterIterator<I> extends AsyncIterator<I> {
constructor(source: AsyncIterator<I>, filter: (item: I) => boolean) {
super();
source.on('readable', () => {
this.emit('readable');
});
let item: I | null;
this.read = (): I | null => {
let item;
while ((item = source.read()) !== null) {
if (filter(item))
return item;
}
// @ts-ignore
if (source._state === ENDED || source._state === CLOSED)
this._end();
return null;
};
}
}
const generateArr = (): number[] => {
let i = 0;
return new Array(200000)
.fill(true)
.map(() => i++);
};
const time = (createStream: (arr: number[]) => AsyncIterator<number> | CompositeMapFilter<number> | CompositeMapFilterFast<number> | CompositeMapFilterVeryFast<number> | CompositeMapFilterVeryVeryFast<number>): Promise<number> => {
const arr = generateArr();
const str = createStream(arr);
let count = 0;
return new Promise((resolve, reject) => {
const now = Date.now();
str.on('data', () => {
count += 1;
})
.on('end', () => {
const then = Date.now();
// if (count != arr.length / 2) {
// console.log(count, arr.length / 2)
// reject(new Error('Bad count'));
// return;
// }
resolve(then - now);
});
})
}
const main = async () => {
const mapArrayMethodTime = await time((arr) => {
let iterator: AsyncIterator<number> = new ArrayIterator(arr);
for (let i = 0; i < 50; i++) {
iterator = iterator.filter(item => item % 2 === 0);
iterator = iterator.map(item => item);
}
return iterator;
});
const mapOldArrayMethodTime = await time((arr) => {
let iterator: any = new OldArrayIterator(arr);
for (let i = 0; i < 50; i++) {
iterator = iterator.filter((item : any) => item % 2 === 0);
iterator = iterator.map((item : any) => item);
}
return iterator;
});
const mapMethodTime = await time((arr) => {
let iterator: AsyncIterator<number> = range(0, arr.length - 1);
for (let i = 0; i < 50; i++) {
iterator = iterator.filter(item => item % 2 === 0);
iterator = iterator.map(item => item);
}
return iterator;
});
const mappingIteratorTime = await time((arr) => {
let iterator: AsyncIterator<number> = range(0, arr.length - 1);
for (let i = 0; i < 50; i++) {
iterator = new FilterIterator(iterator, item => item % 2 === 0);
iterator = new MappingIterator(iterator, item => item);
}
return iterator;
});
const compIteratorTime = await time((arr) => {
let iterator: CompositeMapFilter<number> = new CompositeMapFilter(range(0, arr.length - 1));
for (let i = 0; i < 50; i++) {
iterator = iterator.filter(item => item % 2 === 0);
iterator = iterator.map(item => item);
}
return iterator;
});
const compFastIteratorTime = await time((arr) => {
let iterator: CompositeMapFilterFast<number> = new CompositeMapFilterFast(range(0, arr.length - 1));
for (let i = 0; i < 50; i++) {
iterator = iterator.filter(item => item % 2 === 0);
iterator = iterator.map(item => item);
}
return iterator;
});
// const compVeryFastIteratorTime = await time((arr) => {
// let iterator: CompositeMapFilterVeryFast<number> = new CompositeMapFilterVeryFast(range(0, arr.length - 1));
// for (let i = 0; i < 50; i++) {
// iterator = iterator.filter(item => item % 2 === 0);
// iterator = iterator.map(item => item);
// }
// iterator.build();
// return iterator;
// });
const compVeryVeryFastIteratorTime = await time((arr) => {
let iterator: CompositeMapFilterVeryVeryFast<number> = new CompositeMapFilterVeryVeryFast(range(0, arr.length - 1));
for (let i = 0; i < 50; i++) {
iterator = iterator.filter(item => item % 2 === 0);
iterator = iterator.map(item => item);
}
iterator.build();
return iterator;
});
console.log(`OldArrayIterator#map(): ${mapOldArrayMethodTime}`);
console.log(`ArrayIterator#map(): ${mapArrayMethodTime}`);
console.log(`rangeIterator#map(): ${mapMethodTime}`);
console.log(`MappingIterator: ${mappingIteratorTime}`);
console.log(`CompositeIterator: ${compIteratorTime}`);
console.log(`Composite'Fast'Iterator: ${compFastIteratorTime}`);
// console.log(`CompositeVeryFastIterator: ${compVeryFastIteratorTime}`);
console.log(`CompositeVeryVeryFastIterator: ${compVeryVeryFastIteratorTime}`);
};
main().catch((err) => {
console.error(err);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment