问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

asynctask重写的doinbackground为什么不执行

发布网友 发布时间:2022-04-22 19:19

我来回答

2个回答

懂视网 时间:2022-04-22 23:40

并发相信对大家来说都不陌生,这篇文章主要给大家介绍了关于使用async、enterproxy控制并发数量的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面一起学习学习吧。

聊聊并发与并行

并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

并发我们经常提及之,不管是web server,app并发无处不在,操作系统中,指一个时间段中几个程序处于已经启动运行到完毕之间,且这几个程序都是在同一处理机上运行,并且任一个时间点只有一个程序在处理机上运行。很多网站都有并发连接数量的限制,所以当请求发送太快的时候会导致返回值为空或报错。更有甚者,有些网站可能因为你发出的并发连接数量过多而当你是在恶意请求,封掉你的ip。

相对于并发,并行可能陌生了不少,并行指一组程序按独立异步的速度执行,不等于时间上的重叠(同一个时刻发生),通过增加cpu核心来实现多个程序(任务)的同时进行。没错,并行做到了多任务的同时进行

使用enterproxy控制并发数量

enterproxy是朴灵大大为主要贡献的工具,带来一种事件式编程的思维变化,利用事件机制解耦复杂业务逻辑,解决了回调函数耦合性的诟病,将串行等待变成并行等待,提升多异步协作场景下的执行效率

我们如何使用enterproxy控制并发数量?通常如果我们不使用enterproxy和自制的计数器,我们如果抓取三个源:

这种深层嵌套,串行的方式

 var render = function (template, data) {
 _.template(template, data);
 };
$.get("template", function (template) {
 // something
 $.get("data", function (data) {
 // something
 $.get("l10n", function (l10n) {
 // something
 render(template, data, l10n);
 });
 });
});

除去这种过去深层嵌套的方法,我们常规的写法的自己维护一个计数器

(function(){
 var count = 0;
 var result = {};
 
 $.get('template',function(data){
 result.data1 = data;
 count++;
 handle();
 })
 $.get('data',function(data){
 result.data2 = data;
 count++;
 handle();
 })
 $.get('l10n',function(data){
 result.data3 = data;
 count++;
 handle();
 })

 function handle(){
 if(count === 3){
 var html = fuck(result.data1,result.data2,result.data3);
 render(html);
 }
 }
})();

在这里,enterproxy就可以起到这个计数器的作用,它帮你管理这些异步操作是否完成,完成之后,他会自动调用你提供的处理函数,并将抓取到数据当做参数传递过来

var ep = new enterproxy();
ep.all('data_event1','data_event2','data_event3',function(data1,data2,data3){
 var html = fuck(data1,data2,data3);
 render(html);
})

$.get('http:example1',function(data){
 ep.emit('data_event1',data);
})

$.get('http:example2',function(data){
 ep.emit('data_event2',data);
})

$.get('http:example3',function(data){
 ep.emit('data_event3',data);
})

enterproxy还提供了其他不少场景所需的API,可以自行学习下这个API enterproxy

使用async控制并发数量

假如我们有40个请求需要发出,很多网站可能会因为你发出的并发连接数太多而当你是在恶意请求,把你的IP封掉。
所以我们总是需要控制并发数量,然后慢慢抓取完这40个链接。

使用async中mapLimit控制一次性并发数量为5,一次性只抓取5个链接。

 async.mapLimit(arr, 5, function (url, callback) {
 // something
 }, function (error, result) {
 console.log("result: ")
 console.log(result);
 })

我们首先应该知道什么是并发,为什么需要限制并发数量,都有哪些处理方案。然后就可以去文档具体看一下API如何使用。async文档可以很好的学习这些语法。

模拟一组数据,这里返回的数据是假的,返回的延时是随机的。

var concurreyCount = 0;
var fetchUrl = function(url,callback){
 // delay 的值在 2000 以内,是个随机的整数 模拟延时
 var delay = parseInt((Math.random()* 10000000) % 2000,10);
 concurreyCount++;
 console.log('现在并发数是 ' , concurreyCount , ' 正在抓取的是' , url , ' 耗时' + delay + '毫秒');
 setTimeout(function(){
 concurreyCount--;
 callback(null,url + ' html content');
 },delay);
}

var urls = [];
for(var i = 0;i<30;i++){
 urls.push('http://datasource_' + i)
}

然后我们使用async.mapLimit来并发抓取,并获取结果。

async.mapLimit(urls,5,function(url,callback){
 fetchUrl(url,callbcak);
},function(err,result){
 console.log('result: ');
 console.log(result);
})

模拟摘自alsotang

运行输出后得到以下结果

我们发现,并发数从1开始增长,但是增长到5时,就不在增加。然有任务时就继续抓取,并发连接数量始终控制在5个。

完成node简易爬虫系统

因为alsotang前辈的《node包教不包会》教程例子中使用的eventproxy控制的并发数量,我们就来完成一个使用async控制并发数量的node简易爬虫。

爬取的目标就是本站首页(手动护脸)

第一步,首先我们需要用到以下的模块:

  • url : 用于url解析,这里用到url.resolve()生成一个合法的域名

  • async : 一个实用的模块,提供了强大的功能和异步JavaScript工作

  • cheerio : 为服务器特别定制的,快速,灵活,实施的jQuery核心实现

  • superagent : nodejs里一个非常方便的客户端请求代理模块

  • 通过npm安装依赖模块

    第二步,通过require引入依赖模块,确定爬取对象URL:

    var url = require("url");
    var async = require("async");
    var cheerio = require("cheerio");
    var superagent = require("superagent");
    var baseUrl = 'http://www.chenqaq.com';

    第三步:使用superagent请求目标URL,并使用cheerio处理baseUrl得到目标内容url,并保存在数组arr中

    superagent.get(baseUrl)
     .end(function (err, res) {
     if (err) {
     return console.error(err);
     }
     var arr = [];
     var $ = cheerio.load(res.text);
     // 下面和jQuery操作是一样一样的..
     $(".post-list .post-title-link").each(function (idx, element) {
     $element = $(element);
     var _url = url.resolve(baseUrl, $element.attr("href"));
     arr.push(_url);
     });
     // 验证得到的所有文章链接集合
     output(arr);
     // 第四步:接下来遍历arr,解析每一个页面需要的信息
    })

    我们需要一个函数验证抓取的url对象,很简单我们只需要一个函数遍历arr并打印出来就可以:

    function output(arr){
     for(var i = 0;i<arr.length;i++){
     console.log(arr[i]);
     }
    }

    第四步:我们需要遍历得到的URL对象,解析每一个页面需要的信息。

    这里就需要用到async控制并发数量,如果你上一步获取了一个庞大的arr数组,有多个url需要请求,如果同时发出多个请求,一些网站就可能会把你的行为当做恶意请求而封掉你的ip

    async.mapLimit(arr,3,function(url,callback){
     superagent.get(url)
     .end(function(err,mes){
     if(err){
     console.error(err);
     console.log('message info ' + JSON.stringify(mes));
     }
     console.log('「fetch」' + url + ' successful!');
     var $ = cheerio.load(mes.text);
     var jsonData = {
     title:$('.post-card-title').text().trim(),
     href: url,
     };
     callback(null,jsonData);
     },function(error,results){
     console.log('results ');
     console.log(results);
     })
     })

    得到上一步保存url地址的数组arr,限制最大并发数量为3,然后用一个回调函数处理 「该回调函数比较特殊,在iteratee方法中一定要调用该回调函数,有三种方式」

  • callback(null) 调用成功

  • callback(null,data) 调用成功,并且返回数据data追加到results

  • callback(data) 调用失败,不会再继续循环,直接到最后的callback

  • 好了,到这里我们的node简易的小爬虫就完成了,来看看效果吧

    嗨呀,首页数据好少,但是成功了呢。

    参考资料

    Node.js 包教不包会 - alsotang

    enterproxy

    async

    async Documentation

    上面是我整理给大家的,希望今后会对大家有帮助。

    相关文章:

    在js中如何实现登录需要滑动验证

    在js中如何实现判断文件类型大小

    在vue中如何使用cdn优化

    热心网友 时间:2022-04-22 20:48

    AsyncTask的内幕
    AsyncTask
    主要有二个部分:一个是与主线各的交互,另一个就是线程的管理调度。虽然可能多个AsyncTask的子类的实例,但是AsyncTask的内部
    Handler和ThreadPoolExecutor都是进程范围内共享的,其都是static的,也即属于类的,类的属性的作用范围是
    CLASSPATH,因为一个进程一个VM,所以是AsyncTask控制着进程范围内所有的子类实例。
    与主线程交互
    与主线程交互是通过Handler来进行的,因为本文主要探讨AsyncTask在任务调度方面的,所以对于这部分不做细致介绍,感兴趣的朋友可以去看AsyncTask的源码
    线程任务的调度

    部会创建一个进程作用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask#execute()后,AsyncTask会把任务交给线
    程池,由线程池来管理创建Thread和运行Therad。对于内部的线程池不同版本的Android的实现方式是不一样的:
    Android2.3以前的版本,也即SDK/API 10和以前的版本

    部的线程池*是5个,也就是说同时只能有5个线程运行,超过的线程只能等待,等待前面的线程某个执行完了才被调度和运行。换句话说,如果一个进程中的
    AsyncTask实例个数超过5个,那么假如前5个都运行很长时间的话,那么第6个只能等待机会了。这是AsyncTask的一个*,而且对于2.3
    以前的版本无法解决。如果你的应用需要大量的后台线程去执行任务,那么你只能放弃使用AsyncTask,自己创建线程池来管理Thread,或者干脆不
    用线程池直接使用Thread也无妨。不得不说,虽然AsyncTask较Thread使用起来比较方便,但是它最多只能同时运行5个线程,这也大大局限
    了它的实力,你必须要小心的设计你的应用,错开使用AsyncTask的时间,尽力做到分时,或者保证数量不会大于5个,否则就可能遇到上面提到的问题。
    要不然就只能使用JavaSE中的API了。

    Android 3.0以后,也即SDK/API 11和以后的版本
    可能是Google意识到了AsyncTask的局限性了,从Android 3.0开始对AsyncTask的API做出了一些调整:
    #execute()提交的任务,按先后顺序每次只运行一个
    也就是说它是按提交的次序,每次只启动一个线程执行一个任务,完成之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务(Executors.newSingleThreadPool())。

    新增了接口#executeOnExecutor()

    个接口允许开发者提供自定义的线程池来运行和调度Thread,如果你想让所有的任务都能并发同时运行,那就创建一个没有*的线程池
    (Executors.newCachedThreadPool()),并提供给AsyncTask。这样这个AsyncTask实例就有了自己的线程池
    而不必使用AsyncTask默认的。
    新增了二个预定义的线程池SERIAL_EXECUTOR和THREAD_POOL_EXECUTOR
    其实THREAD_POOL_EXECUTOR并不是新增的,之前的就有,只不过之前(Android 2.3)它是AsyncTask私有的,未公开而已。THREAD_POOL_EXECUTOR是一个corePoolSize为5的线程池,也就是说最多只有5个线程同时运行,超过5个的就要等待。所以如果使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)就跟2.3版本的AsyncTask.execute()效果是一样的。

    而SERIAL_EXECUTOR是
    新增的,它的作用是保证任务执行的顺序,也就是它可以保证提交的任务确实是按照先后顺序执行的。它的内部有一个队列用来保存所提交的任务,保证当前只运行
    一个,这样就可以保证任务是完全按照顺序执行的,默认的execute()使用的就是这个,也就是
    executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)与execute()是一样的。
    前面问题的解法

    解了AsyncTask的内幕就知道了前面问题的原因:因为是4.0平台,所以所有的AsyncTask并不都会运行在单独的线程中,而是被
    SERIAL_EXECUTOR顺序的使用线程执行。因为应用中可能还有其他地方使用AsyncTask,所以到网络取图片的AsyncTask也许会等
    待到其他任务都完成时才得以执行而不是调用executor()之后马上执行。

    么解决方法其实很简单,要么直接使用Thread,要么创建一个单独的线程池(Executors.newCachedThreadPool())。或者
    最简单的解法就是使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR),这样起码不用等到前面的都
    结束了再执行。
    AsyncTask的使用注意事项
    前面的文章曾建议使用AsyncTask而不是使用Thread,但是AsyncTask似乎又有它的*,这就要根据具体的需求情况而选择合适的工具,No Silver Bullet。下面是一些建议:
    改善你的设计,少用异步处理
    线程的开销是非常大的,同时异步处理也容易出错,难调试,难维护,所以改善你的设计,尽可能的少用异步。对于一般性的数据库查询,少量的I/O操作是没有必要启动线程的。
    与主线程有交互时用AsyncTask,否则就用Thread
    AsyncTask被设计出来的目的就是为了满足Android的特殊需求:非主线程不能操作(UI)组件,所以AsyncTask扩展Thread增强了与主线程的交互的能力。如果你的应用没有与主线程交互,那么就直接使用Thread就好了。
    当有需要大量线程执行任务时,一定要创建线程池
    线
    程的开销是非常大的,特别是创建一个新线程,否则就不必设计线程池之类的工具了。当需要大量线程执行任务时,一定要创建线程池,无论是使用
    AsyncTask还是Thread,因为使用AsyncTask它内部的线程池有数量*,可能无法满足需求;使用Thread更是要线程池来管理,避
    免虚拟机创建大量的线程。比如从网络上批量下载图片,你不想一个一个的下,或者5个5个的下载,那么就创建一个CorePoolSize为10或者20的
    线程池,每次10个或者20个这样的下载,即满足了速度,又不至于耗费无用的性能开销去无*的创建线程。
    对于想要立即开始执行的异步任务,要么直接使用Thread,要么单独创建线程池提供给AsyncTask
    默认的AsyncTask不一定会立即执行你的任务,除非你提供给他一个单独的线程池。如果不与主线程交互,直接创建一个Thread就可以了,虽然创建线程开销比较大,但如果这不是批量操作就没有问题。
    Android的开发没有想像中那样简单,要多花心思和时间在代码上和测试上面,以确信程序是优质的
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    低温还原粉化性检验方法 ...播放量破50亿,大胃王“浪胃仙”是如何在抖音崛起的? 网络直播间:新部落的建构及其亚文化特征 网络直播中吃播的文化输出 我用圆通快递从河南商丘发到洛阳几天能到 商丘圆通快递几点下班? 河南商丘到江苏南京圆通快递,大概要多久? 四大名著语录 “命中注定我爱你”真的好看么? 好看的偶像剧 命中注定我爱你 农村商业银行是不是农业银行 现在新冠疫情那么严重,河南洛阳下单的快递发广东的到底能不能收啊? 疫情期间快递还能运行吗 秋已暮露成霜什么意思? 给老师的一封信,要有真实的事例 WDM驱动的程序结构 各位亲们,有谁做的毕业设计是(基于单片机的车削数控运动控制)啊,或者差不多的论题也行啊。 和国旗拍照有什么禁忌吗 给红旗合影照片怎么弄 开衫毛线衣外套怎么搭配 为什么java已经有线程池的实现了,还要继续使用asynctask 求段姓男孩名字!有创意的!请文明回答! 段氏姓名好听的男孩名字 孩子读书统一社会信用代码怎么填 四年级介绍自己学习生活的书信 httpclient在并发量较高的调用下问题如何去 10篇小学精短暑假日记.200字以下. 10篇暑假日记不超过200字。 现在农村50多岁的人,一般用什么手机? 合肥恒大中央广场20楼9楼的平面图 恒大中央广场到合肥火车站怎么走 组合贷款,公积金部分是建行贷款的,商贷部分能不能从其他银行贷款? 为什么俄罗斯不提前把外汇储备清空 俄罗斯卢布为什么不值钱 士兵转士官具体怎么做! 部队对转士官的人有啥要求! 无力偿还贷款怎么办 失恋了怎么办?? 新兵下连后被派去学习…中途被团长看中,叫去当文书。请问当文书是干嘛的呀?有前途吗?! iphone4怎么换主题 为什么说只有平等相伴,有退有进的感情才能长长久久? 买海尔冰箱厂家会不会给我2手的 写我身边的敬老故事,那个开头千万不要写佬吾老以及人之老,幼吾幼以及人之幼。也不要写,尊老爱幼自古以 如何才是真正尊敬别人呢? 我男朋友发这个,我要怎么说呢,他说要我尊重,他让我尊重他什么呢,他发这个我要怎么说呢,大家帮帮我吧 wcf 并发量多少 小米授权店有点烟器充电器没 哪里有卖车载充电器和点烟器两用 高速服务区有点烟器插口充电器卖吗 我想买个汽车充电器、就是点烟器转换插座那种(两个小孔那个插座) 现在有没有U口点烟器示的充电器