cc.loader加载网络图片的并发线程数,是否可控制

您好,我看了一下cc.loader的实现代码,发现是用jsb.loadRemoteImg加载网络图片的,JSB层是__JSDownloaderDelegator::downloadAsync,里面开了新线程创建的Downloader。

因为我的应用里要显示卡牌列表,都是从网络加载的图片,一个listView里有很多item,每个item里面都是用cc.loader.load(url, cb)加载的网络图片,同时显示20个item的话,担心底层开20个线程会影响性能,所以想问问是否可以控制最大并发线程数呢?

我在看底层代码时,发现本来在load-pipeline\downloader.js的handle中是可以控制并发数的,但是由于在jsb-loader.js中把图片的handler设置为empty,导致downloader的handle立刻就结束,而把下载工作转移给了jsb-loader.js的loadImage,这个并发控制就没起作用。然后就是在CCDownloader.cpp的构造函数中本来也可以控制任务并发数,但由于在__JSDownloaderDelegator::startDownload中每次创建的_downloader对象只下载一个url,即_downloader->createDownloadDataTask(_url),导致在CCDownloader中设置的并发数也不起作用。

我现在想仿照load-pipeline\downloader.js中_curConcurrent和_loadQueue的逻辑,在jsb-loader.js的loadImage中实现并发下载数量的控制,您觉得这个想法可行吗?

谢谢!

1赞

可行 :+1::+1::+1:

呃,@panda 你怎么会每次 downloadAsync 都新开一个线程呢。游戏里面网络应该是始终只有一个线程,和加载线程之间用生产者-消费者模型来做数据交换及互锁啊。

Downloader 是不同的文件不同线程的,为了并发,互锁机制这些 @dumganhar 已经加了的

我最终的实现代码,给大家做个参考吧,参照downloader.js在loader.js里改的

var Loader = function (extMap) {
    this.id = ID;
    this.async = true;
    this.pipeline = null;

    this.maxConcurrent = cc.sys.isMobile ? 5 : 512;
    this._curConcurrent = 0;
    this._loadQueue = [];

    this.extMap = JS.mixin(extMap, defaultMap);
};

Loader.ID = ID;
JS.mixin(Loader.prototype, {
    /**
     * Add custom supported types handler or modify existing type handler.
     * @method addHandlers
     * @param {Object} extMap Custom supported types with corresponded handler
     */
    addHandlers: function (extMap) {
        this.extMap = JS.mixin(this.extMap, extMap);
    },

    handle: function (item, callback) {
        var self = this;
        var loadFunc = this.extMap[item.type] || this.extMap['default'];

        if (CC_EDITOR || item.type == "uuid") //uuid有依赖加载,不能简单地放入并发队列
        {
            loadFunc.call(this, item, function (err, result) {
                if (err) {
                    callback && callback(err);
                }
                else {
                    callback && callback(null, result);
                }
            });
            return;
        }
        
        //对非"uuid"类型加入了并发数量控制
        if (this._curConcurrent < this.maxConcurrent) {
            this._curConcurrent++;
            loadFunc.call(this, item, function (err, result) {
                if (err) {
                    callback && callback(err);
                } else {
                    callback && callback(null, result);
                }

                // Concurrent logic
                self._curConcurrent = Math.max(0, self._curConcurrent - 1);
                var delta = self.maxConcurrent - self._curConcurrent;
                for(var i = 0; i < delta; ++i) {
                    var nextOne = self._loadQueue.shift();
                    if (nextOne) {
                        self.handle(nextOne.item, nextOne.callback);
                    }else{
                        break;
                    }
                }
            });
        }
        else {
            this._loadQueue.push({
                item: item,
                callback: callback
            });
        }        
    }
});
3赞