tusharmath / Multi-threaded-downloader

A http file downloader made in nodejs
MIT License
194 stars 90 forks source link

How can I do to get the file fast #166

Open cecilpeng opened 7 years ago

cecilpeng commented 7 years ago

If I can change the config: range or meteWrite. I tested to download 60M file.

Chrome: 1min. Here: 7min.

tusharmath commented 7 years ago

I am not sure why it's slower than chrome. Some more detail might help here.

cecilpeng commented 7 years ago

I am unfamiliar with Rxjs, so i spent much time to learn. I am confused that it logs double even four request. Maybe some bug in the module of http request.

This is my code, just copied from TestHelper.js

const fs = require('fs');
const mtdownloader = require('mt-downloader');
const muxer = require('muxer');
const Rx = require('rx');
const R = require('ramda');
const Q = require('q');

function download(options) {
    /**
     * 1. 判断是否存在mtd文件,否则生成mtd文件
     * 2. 根据mtd文件下载
     * 3. 删除meta信息及mtd文件
     * 4. 结束
     */
    const mtdPath = mtdownloader.MTDPath(options.path);

    const createMTDFile$ = Rx.Observable.fromPromise(new Promise((resolve, reject) => {
        fs.stat(mtdPath, (err) => {
            if (err) {
                mtdownloader.CreateMTDFile(options).toPromise().then(resolve, reject);
            } else {
                resolve();
            }
        });
    }));

    const downloadFromMTDFile$ = createMTDFile$.map(mtdPath).flatMap(mtdownloader.DownloadFromMTDFile).share();
    const [{ fdR$, meta$ }] = muxer.demux(downloadFromMTDFile$, 'meta$', 'fdR$');

    const finalizeDownload$ = downloadFromMTDFile$.last()
        .withLatestFrom(fdR$, meta$, (_, fd, meta) => ({
            fd$: Rx.Observable.just(fd),
            meta$: Rx.Observable.just(meta)
        }))
        .flatMap(mtdownloader.FinalizeDownload)
        .share()
        .last();

    const fd$ = finalizeDownload$
        .withLatestFrom(fdR$)
        .map(R.tail)
        .flatMap(R.map(R.of));

    let defer = Q.defer();

    const complete$ = mtdownloader.FILE.close(fd$);
    const progress$ = mtdownloader.Completion(meta$).throttle(100);

    complete$.subscribe(() => {
        defer.notify(1);
        defer.resolve();
    }, defer.reject);
    progress$.subscribe((progress) => {
        defer.notify(progress);
    });

    return defer.promise;
}

module.exports = download;

Test code:

download({
            path: path.join(os.tmpdir(), 'hehe.pptx'),
            url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171.pptx',
            range: 1
        }).then(() => done(), undefined, (progress) => console.log(progress));

I injected console.log into module request. Logs below:

IO requestHead

{ range: 1,
  metaWrite: 300,
  mtdPath: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx.mtd',
  path: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx',
  url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171
.pptx' }
{ range: 1,
  metaWrite: 300,
  mtdPath: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx.mtd',
  path: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx',
  url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171
.pptx' }

RequestThread

{ range: 1,
  metaWrite: 300,
  mtdPath: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx.mtd',
  path: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx',
  url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171
.pptx',
  totalBytes: 2441878,
  headers: { range: 'bytes=0-2441878' } }
{ range: 1,
  metaWrite: 300,
  mtdPath: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx.mtd',
  path: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx',
  url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171
.pptx',
  totalBytes: 2441878,
  headers: { range: 'bytes=0-2441878' } }
{ range: 1,
  metaWrite: 300,
  mtdPath: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx.mtd',
  path: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx',
  url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171
.pptx',
  totalBytes: 2441878,
  headers: { range: 'bytes=0-2441878' } }
{ range: 1,
  metaWrite: 300,
  mtdPath: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx.mtd',
  path: 'C:\\Users\\CQQ\\AppData\\Local\\Temp\\hehe.pptx',
  url: 'http://dev-c1024.yunkai.com/dev/doc/fdf28226-2261-479e-86ca-755797973171
.pptx',
  totalBytes: 2441878,
  headers: { range: 'bytes=0-2441878' } }
0
0.01
0.02

Complete code: http://oixk4v2c8.bkt.clouddn.com/downloader-master.zip

tusharmath commented 7 years ago

@cecilpeng I think that's happening because the stream is not multicasted. Checkout http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-share to understand multicasting.