对于Android移动应用的开发者来说,耗电量的控制一直是个老大难问题。
我们想要控制耗电量,必须要有工具或者方法比较准确的定位应用的耗电情况。下面,我们先来分析下如何计算android应用的耗电量。
在android自带的设置里面有电量计算的界面,如下图:
<ignore_js_op>
我们看下是如何实现的:
在android framework里面有专门负责电量统计的Service:BatteryStatsSerive。这个Service在ActivityManagerService中创建,代码如下:
1 |
mBatteryStatsService = new BatteryStatsService(new File(systemDir, 'batterystats.bin').toString()); |
其他的模块比如WakeLock和PowerManagerService会向BatteryStatsService喂数据,数据是存放到系统目录batterystats.bin文件,然后交于BatteryStatsImpl这个数据分析器来进行电量数据的分析,系统的设置就是这样得到电量的统计信息的。
拿到相关的数据后,电量的计算又是如何得出的呢?这里用到了如下的计算公式:
应用运行总时间 = 应用在Linux内核态运行时间 + 应用在Linux用户态运行时间
CPU工作总时间 = 软件运行期间CPU每个频率下工作的时间之和比例
应用消耗的电量 = CPU每个频率等级下工作的时间比例/CPU工作总时间 * 应用运行总时间
* 不同频率下消耗的电量 + 数据传输消耗的电量(WI-FI或者移动网络)+ 使用所有传感器消耗的电量 + 唤醒锁消耗的电量。
相应的代码片段如下:
001 |
private void processAppUsage() { |
002 |
SensorManager sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); |
003 |
final int which = mStatsType; |
004 |
final int speedSteps = mPowerProfile.getNumSpeedSteps(); |
005 |
final double[] powerCpuNormal = new double[speedSteps]; |
006 |
final long[] cpuSpeedStepTimes = new long[speedSteps]; |
007 |
for (int p = 0; p < speedSteps; p++) { |
008 |
powerCpuNormal[p] = mPowerProfile.getAveragePower |
009 |
PowerProfile.POWER_CPU_ACTIVE, p); |
011 |
final double averageCostPerByte = getAverageDataCost(); |
012 |
long uSecTime = mStats.computeBatteryRealtime( |
013 |
SystemClock.elapsedRealtime() * 1000, which); |
014 |
mStatsPeriod = uSecTime; |
016 |
SparseArray<? extends Uid> uidStats = mStats.getUidStats(); |
017 |
final int NU = uidStats.size(); |
018 |
for (int iu = 0; iu < NU; iu++) { |
019 |
Uid u = uidStats.valueAt(iu); |
021 |
double highestDrain = 0; |
022 |
String packageWithHighestDrain = null; |
023 |
Map<String, ? extends BatteryStats.Uid.Proc> proce ssStats = u.getProcessStats(); |
027 |
if (processStats.size() > 0) { |
029 |
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent : processStats.entrySet()) { |
031 |
Log.i(TAG, 'Process name = ' + ent.getKey()); |
032 |
Uid.Proc ps = ent.getValue(); |
033 |
final long userTime = ps.getUserTime(which); |
034 |
final long systemTime = ps.getSystemTime(which); |
035 |
final long foregroundTime = ps.getForegroundTime(which); |
036 |
cpuFgTime += foregroundTime * 10; // convert to millis |
037 |
final long tmpCpuTime = (userTime + systemTime) * 10; // convert to millis |
038 |
int totalTimeAtSpeeds = 0; |
039 |
// Get the total first |
040 |
for (int step = 0; step < speedSteps; step++) { |
041 |
cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which); |
042 |
totalTimeAtSpeeds += cpuSpeedStepTimes[step]; |
044 |
if (totalTimeAtSpeeds == 0) |
045 |
totalTimeAtSpeeds = 1; |
046 |
// Then compute the ratio of time spent at each speed |
047 |
double processPower = 0; |
048 |
for (int step = 0; step < speedSteps; step++) { |
049 |
double ratio = (double) cpuSpeedStepTimes[step]/ totalTimeAtSpeeds; |
050 |
processPower += ratio * tmpCpuTime* powerCpuNormal[step]; |
052 |
cpuTime += tmpCpuTime; |
053 |
power += processPower; |
054 |
if (highestDrain < processPower) { |
055 |
highestDrain = processPower; |
056 |
packageWithHighestDrain = ent.getKey(); |
063 |
cpuTime = cpuFgTime; // Statistics may not have been gathered yet. |
067 |
// Add cost of data traffic |
068 |
long tcpBytesReceived = u.getTcpBytesReceived(mStatsType); |
069 |
long tcpBytesSent = u.getTcpBytesSent(mStatsType); |
070 |
power += (tcpBytesReceived + tcpBytesSent) * averageCostPerByte; |
072 |
// Process Sensor usage |
073 |
Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); |
074 |
for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> sensorEntry : sensorStats.entrySet()) { |
075 |
Uid.Sensor sensor = sensorEntry.getValue(); |
076 |
int sensorType = sensor.getHandle(); |
077 |
BatteryStats.Timer timer = sensor.getSensorTime(); |
078 |
long sensorTime = timer.getTotalTimeLocked(uSecTime, which) / 1000; |
079 |
double multiplier = 0; |
080 |
switch (sensorType) { |
082 |
multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); |
083 |
gpsTime = sensorTime; |
086 |
android.hardware.Sensor sensorData = sensorManager |
087 |
.getDefaultSensor(sensorType); |
088 |
if (sensorData != null) { |
089 |
multiplier = sensorData.getPower(); |
093 |
power += (multiplier * sensorTime) / 1000; |
096 |
// Add the app to the list if it is consuming power |
098 |
BatterySipper app = new BatterySipper(packageWithHighestDrain,0, u, new double[] { power }); |
099 |
app.cpuTime = cpuTime; |
100 |
app.gpsTime = gpsTime; |
101 |
app.cpuFgTime = cpuFgTime; |
102 |
app.tcpBytesReceived = tcpBytesReceived; |
103 |
app.tcpBytesSent = tcpBytesSent; |
106 |
if (power > mMaxPower) |
108 |
mTotalPower += power; |
110 |
Log.i(TAG, 'Added power = ' + power); |
通过代码我们看到,每个影响电量消耗的base值其实是事先配置好的,在系统res下power_profile.xml,所以通过这个方式计算出来的电量消耗值也只能作为一个经验值或者是参考值,和物理上的耗电值应该还是有所偏差的。
那我们还能用啥方式去比较准确的去获取耗电量呢?我们想到了曹冲称象的故事,可以用差值的方式进行尝试。在相同时间单位内,在没有安装应用的手机上和安装了应用的手机上记录耗电量,取差值为该应用的耗电量。在测试过程中注意几点,保证该手机相对“干净”,开始前需要结束所有的后台程序,将手机电量冲满,保证每次的起步点相同,这里推荐电量监控程序Battery Monitor Widget,这款软件功能比较强大,可以看到历史的电量变化。这两种测试方式可以同时使用,互为印证,已经应用到在Agoo Android SDK的测试中。
拿到电量数据后,紧接着就是如何优化电量的问题了。通过电量的计算公式我们可以看到影响电量的因子无非就是CPU的时间和网络数据以及Wakelock,GPS的使用。
在09年Google IO大会Jeffrey Sharkey的演讲(Coding for Life — Battery Life, That Is)中就探讨了这个问题,指出android应用的耗电主要在以下三个方面:
- 大数据量的传输。
- 不停的在网络间切换。
- 解析大量的文本数据。
并提出了相关的优化建议:
- 在需要网络连接的程序中,首先检查网络连接是否正常,如果没有网络连接,那么就不需要执行相应的程序。
- 使用效率高的数据格式和解析方法,推荐使用JSON和Protobuf。
- 目在进行大数据量下载时,尽量使用GZIP方式下载。
- 其它:回收java对象,特别是较大的java对像,使用reset方法;对定位要求不是太高的话尽量不要使用GPS定位,可能使用wifi和移动网络cell定位即可;尽量不要使用浮点运算;获取屏幕尺寸等信息可以使用缓存技术,不需要进行多次请求;使用AlarmManager来定时启动服务替代使用sleep方式的定时任务。
作为app开发者,或许很少有人会注意app对电量的损耗,但是用户对电量可是很敏感的,app做好电量损耗的优化会为自己的app加分不少。
如果是一个好的负责任的开发者,就应该限制app对电量的影响,当没有网络连接的时候,禁用后台服务更新,当电池电量低的时候减少更新的频率,确保自己的app对电池的影响降到最低。当电池充电或者电量比较饱和时,可以最大限度的发挥app的刷新率
1 |
<receiver android:name=".PowerConnectReceiver"> |
3 |
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> |
4 |
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> |
01 |
public class PowerConnectionReceiver extends BroadcastReceiver { |
03 |
public void onReceive(Context context, Intent intent) { |
04 |
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); |
05 |
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || |
06 |
status == BatteryManager.BATTERY_STATUS_FULL; |
08 |
int chargeFlag = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); |
09 |
boolean usbCharge = chargeFlag == BATTERY_PLUGGED_USB; |
10 |
boolean acCharge = chargeFlag == BATTERY_PLUGGED_AC; |
3 |
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS,-1); |
5 |
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||status == BatteryManager.BATTERY_STATUS_FULL; |
2 |
int chargeFlag = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); |
3 |
boolean usbCharge = chargeFlag == BATTERY_PLUGGED_USB; |
4 |
boolean acCharge = chargeFlag == BATTERY_PLUGGED_AC; |
1 |
不断的检测电量也会影响电池的使用时间,我们可以这样做 |
1 |
<receiver android:name=".BatteryLevelReceiver"> |
3 |
<action android:name="android.intent.action.ACTION_BATTERY_LOW"/> <actionandroid:name="android.intent.action.ACTION_BATTERY_OKAY"/> </intent-filter> |
当电量低或者满时会触发
有时间再写确定和监测连接状态
测试结论:
1)灭屏待机最省电:
a)任何App包括后台Service应该尽可能减少唤醒CPU的次数,比如IM类业务的长连接心跳、QQ提醒待机闹钟类业务的alarm硬时钟唤醒要严格控制;
b)每次唤醒CPU执行的代码应该尽可能少,从而让CPU迅速恢复休眠,比如申请wake lock的数量和持有时间要好好斟酌;
2)Wi-Fi比蜂窝数据,包括2G(GPRS)、3G更省电:
a)尽量在Wi-Fi下传输数据,当然这是废话,不过可以考虑在有Wi-Fi的时候做预加载,比如应用中心的zip包、手Q web类应用的离线资源等;
b)非Wi-Fi下,尽量减少网络访问,每一次后台交互都要考虑是否必须。虽然WiFi接入方式已经占到移动互联网用户的50%,但是是有些手机设置为待机关闭WiFi连接,即便有Wi-Fi信号也只能切换到蜂窝数据;
测试分析:
1)灭屏的情况:
a)灭屏待机,CPU处于休眠状态,最省电(7mA);
b)灭屏传输,CPU被激活,耗电显著增加,即便是处理1K的心跳包,电量消耗也会是待机的6倍左右(45mA);
c)灭屏传输,高负载download的时候WiFi最省电(70mA),3G(270mA)和2G(280mA)相当,是WiFi的4倍左右;
2)亮屏的情况:
a)亮屏待机,CPU处于激活状态,加上屏幕耗电,整机电量消耗不小(140mA);
b)亮屏传输,如果只是处理1K的心跳包,耗电增加不多(150mA),即便是很大的心跳包(64K),消耗增加也不明显(160mA);
c)亮屏传输,高负载download的时候WiFi最省电(280mA),3G(360mA)和2G(370mA)相当,是WiFi的1.3倍左右;
3)Alarm唤醒频繁会导致待机耗电增加:
手机灭屏后会进入待机状态,这时CPU会进入休眠状态。Android的休眠机制介绍的文章很多,这里引用一段网络文章:
Early suspend是android引进的一种机制,这种机制在上游备受争议,这里 不做评论。这个机制作用在关闭显示的时候,在这个时候,一些和显示有关的 设备,比如LCD背光,比如重力感应器,触摸屏,这些设备都会关掉,但是系统可能还是在运行状态(这时候还有wake lock)进行任务的处理,例如在扫描SD卡上的文件等.在嵌入式设备中,背光是一个很大的电源消耗,所以android会加入这样一种机制.
Late Resume是和suspend配套的一种机制,是在内核唤醒完毕开始执行的.主要就是唤醒在Early Suspend的时候休眠的设备.
Wake Lock在Android的电源管理系统中扮演一个核心的角色. Wake Lock是一种锁的机制,只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得.这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁.如果没有锁了或者超时了,内核就会启动休眠的那套机制来进入休眠.
当用户写入mem或者standby到/sys/power/state中的时候, state_store()会被调用,然后Android会在这里调用request_suspend_state()而标准的Linux会在这里进入enter_state()这个函数.如果请求的是休眠,那么early_suspend这个workqueue就会被调用,并且进入early_suspend
简单的说,当用户按power键,使得手机进入灭屏休眠状态,Android系统其实是做了前面说的一些工作:关闭屏幕、触摸屏、传感器、dump当前用户态和内核态程序运行上下文到内存或者硬盘、关闭CPU供电,当然为了支持语音通讯,modern等蜂窝信令还是工作的。
这种情况下,应用要唤醒CPU,只有两种可能:
a)通过服务器主动PUSH数据,通过网络设备激活CPU;
b)设置alarm硬件闹钟唤醒CPU;
这里我们重点分析第二种情况。首先来看看什么是alarm硬件闹钟。Google官方提供的解释是:Android提供的alarm services可以帮助应用开发者能够在将来某一指定的时刻去执行任务。当时间到达的时候,Android系统会通过一个Intent广播通知应用去完成这一指定任务。即便CPU休眠,也不影响alarm services的服务,这种情况下可以选择唤醒CPU。
显然唤醒CPU是有电量消耗的,CPU被唤醒的次数越多,耗电量会越大。现在很多应用为了维持心跳、拉取数据、主动PUSH会不同程度地注册alarm服务,导致Android系统被频繁唤醒。这就是为什么雷军说Android手机在安装了TOP100的应用后,待机时间会大大缩短的重要原因。
比较简单评测CPU唤醒次数的方法是看dumpsys alarm,这里会详细记录从开机到当前的各个进程和服务唤醒CPU的次数和时间。通过对比唤醒次数和唤醒时间可以帮助我们分析后台进程和服务的耗电情况。Dumpsys alarm的输出看起来像这样:
其中544代表唤醒次数,38684ms代表唤醒时间。
4)Wake locks持有时间过长会导致耗电增加:
Wake locks是一种锁机制,有些文献翻译成唤醒锁。简单说,前面讲的灭屏CPU休眠还需要做一个判断,就是看是否还有任何应用持有wake locks。如果有,CPU将不会休眠。有些应用不合理地申请wake locks,或者申请了忘记释放,都会导致手机无法休眠,耗电增加。
原始数据:
测试方法:硬件设备提供稳压电源替代手机电池供电,在不同场景下记录手机平均电流。
测试设备:Monsoon公司的Power Monitor TRMT000141
测试机型:Nexus One
灭屏benchmark(CPU进入休眠状态):7mA
灭屏WiFi:70 mA
灭屏3G net:270 mA
灭屏2G net GPRS:280mA
亮屏benchmark:140mA
亮屏Wi-Fi:280mA
亮屏3G net:360mA
亮屏2G:370mA
亮屏待机:140mA
亮屏Wi-Fi ping 1024包:150mA
亮屏Wi-Fi ping 65500包:160mA
灭屏 屏1024:45mA
灭屏ping 65500:55mA
关闭所有数据网络待机:7mA
显而易见,大部分的电都消耗在了网络连接、GPS、传感器上了。
简单的说也就是主要在以下情况下耗电比较多:
1、 大数据量的传输。
2、 不停的在网络间切换。
3、 解析大量的文本数据。
那么我们怎么样来改善一下我们的程序呢?
1、 在需要网络连接的程序中,首先检查网络连接是否正常,如果没有网络连接,那么就不需要执行相应的程序。
检查网络连接的方法如下:
ConnectivityManager mConnectivity;
TelephonyManager mTelephony;
……
// 检查网络连接,如果无网络可用,就不需要进行连网操作等
NetworkInfo info = mConnectivity.getActiveNetworkInfo();
if (info == null ||
!mConnectivity.getBackgroundDataSetting()) {
return false;
}
//判断网络连接类型,只有在3G或wifi里进行一些数据更新。
int netType = info.getType();
int netSubtype = info.getSubtype();
if (netType == ConnectivityManager.TYPE_WIFI) {
return info.isConnected();
} else if (netType == ConnectivityManager.TYPE_MOBILE
&& netSubtype == TelephonyManager.NETWORK_TYPE_UMTS
&& !mTelephony.isNetworkRoaming()) {
return info.isConnected();
} else {
return false;
}
2、 使用效率高的数据格式和解析方法。
通过测试发现,目前主流的数据格式,使用树形解析(如DOM)和流的方式解析(SAX)对比情况如下图所示:
很明显,使用流的方式解析效率要高一些,因为DOM解析是在对整个文档读取完后,再根据节点层次等再组织起来。而流的方式是边读取数据边解析,数据读取完后,解析也就完毕了。
在数据格式方面,JSON和Protobuf效率明显比XML好很多,XML和JSON大家都很熟悉,Protobuf是Google提出的,一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据串行化方法。有兴趣的可以到官方去看看更多的信息。
从上面的图中我们可以得出结论就是尽量使用SAX等边读取边解析的方式来解析数据,针对移动设备,最好能使用JSON之类的轻量级数据格式为佳。
3、 目前大部门网站都支持GZIP压缩,所以在进行大数据量下载时,尽量使用GZIP方式下载。
使用方法如下所示:
import java.util.zip.GZIPInputStream;
HttpGet request =
new HttpGet("http://example.com/gzipcontent");
HttpResponse resp =
new DefaultHttpClient().execute(request);
HttpEntity entity = response.getEntity();
InputStream compressed = entity.getContent();
InputStream rawData = new GZIPInputStream(compressed);
使用GZIP压缩方式下载数据,能减少网络流量,下图为使用GZIP方式获取包含1800个主题的RSS对比情况。
4、 其它一些优化方法:
回收java对象,特别是较大的java对像
XmlPullParserFactory and BitmapFactory
Matcher.reset(newString) for regex
StringBuilder.sentLength(0)
对定位要求不是太高的话尽量不要使用GPS定位,可能使用wifi和移动网络cell定位即可。GPS定位消耗的电量远远高于移动网络定位。
尽量不要使用浮点运算。
获取屏幕尺寸等信息可以使用缓存技术,不需要进行多次请求。
很多人开发的程序后台都会一个service不停的去服务器上更新数据,在不更新数据的时候就让它sleep,这种方式是非常耗电的,通常情况下,我们可以使用AlarmManager来定时启动服务。如下所示,第30分钟执行一次。
AlarmManager am = (AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent =
PendingIntent.getService(context, 0, intent, 0);
long interval = DateUtils.MINUTE_IN_MILLIS * 30;
long firstWake = System.currentTimeMillis() + interval;
am.setRepeating(AlarmManager.RTC,firstWake, interval, pendingIntent);
最后一招,在运行你的程序前先检查电量,电量太低,那么就提示用户充电之类的,使用方法:
public void onCreate() {
// Register for sticky broadcast and send default
registerReceiver(mReceiver, mFilter);
mHandler.sendEmptyMessageDelayed(MSG_BATT, 1000);
}
IntentFilter mFilter =
new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// Found sticky broadcast, so trigger update
unregisterReceiver(mReceiver);
mHandler.removeMessages(MSG_BATT);
mHandler.obtainMessage(MSG_BATT, intent).sendToTarget();
}
};
- Android 中对于图片的内存优化方法
Android 中对于图片的内存优化方法,需要的朋友可以参考一下 1. 对图片本身进行操作 尽量不要使用 setImageBitmap.setImageResource. BitmapFact ...
- 《高性能iOS 应用开发》之降低你 APP 的电量消耗
在编写高性能 代码时, 电量消耗是一个需要重点处理的重要因素, 就执行时间和 CPU 资源的利用而言, 我们不仅要实现高效的数据结构和算法, 还需要考虑其他的因素,如果某个应用是个电池黑洞,那么一定不 ...
- Android内核开发:系统启动速度优化-Android OS启动优化(转)
Android系统的启动优化主要分为三大部分: (1) Bootloader优化 (2) Linux Kernel的剪裁与优化 (3) Android OS部分的剪裁与优化 本文重点关注Android ...
- Android UI学习 - FrameLayou和布局优化(viewstub)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://android.blog.51cto.com/268543/308090 Fram ...
- I.MX6 android 禁止低电量自动关机
/************************************************************************ * I.MX6 android 禁止低电量自动关机 ...
- android电池充电以及电量检测驱动分析
前段时间比较烦躁,各种不想学习不想工作,于是休息了几天.这几天又下来任务了--调试充电电路和电池电量检测电路,于是又开始工作,顺便把调试过程记录下来. 平台: cpu 飞思卡尔imx6q ...
- Unity3D获取Android平台的电量
刚开始的时候以为这个应该不简单.我也开始百度,寻找获取手机的电量的方法.大概有俩种方式:一种是直接访问一个文件,意思是说Android手机的电量等信息保存到了这个文件中.但是我试验的时候没有访问出来, ...
- Android实习生 —— 屏幕适配及布局优化
为什么要进行屏幕适配.对哪些设备进行适配?在近几年的发展当中,安卓设备数量逐渐增长,由于安卓设备的开放性,导致安卓设备的屏幕尺寸大小碎片化极为严重.从[友盟+]2016年手机生态发展报告H1中看截止1 ...
- 【腾讯bugly干货分享】Android自绘动画实现与优化实战——以Tencent OS录音机波形动
前言 本文为腾讯bugly的原创内容,非经过本文作者同意禁止转载,原文地址为:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1180 ...
随机推荐
- 《Java性能权威指南》笔记----Java性能调优工具
OS 1.CPU 用户态时间(us):cpu执行应用代码所占时间的百分比. 内核态时间(sy):cpu执行内核代码所占时间的百分比,系统态时间与应用相关. 空闲时间(id):cpu空闲时间百分比.空闲 ...
- 33个好用的图片轮显 jquery图片轮显
原文发布时间为:2011-05-28 -- 来源于本人的百度文章 [由搬家工具导入] 我个人还是喜欢 jquery.recycle,比较通用。因为由美工设计好的轮显结构,如果套用下面,就感觉不是很方便 ...
- DOS头结构
DOS头结构typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header +0h WORD e_magic; ...
- hexo添加百度统计
litten的主题yilia 编辑文件 themes/yilia/_config.yml,添加一行配置,可以删除原来的google analytics baidu_tongji: true 新建 th ...
- HDU 1998 奇数阶魔方【模拟填数/注意边界和细节】
奇数阶魔方 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- 大话Spark(4)-一文理解MapReduce Shuffle和Spark Shuffle
Shuffle本意是 混洗, 洗牌的意思, 在MapReduce过程中需要各节点上同一类数据汇集到某一节点进行计算,把这些分布在不同节点的数据按照一定的规则聚集到一起的过程成为Shuffle. 在Ha ...
- NBNS扫描工具nbtscan-unixwiz
NBNS扫描工具nbtscan-unixwiz NBNS是NetBIOS Name Service的缩写,表示NetBIOS名称解析服务.NETBIOS是一种网络协议,用于实现消息通信和资源共享.利用 ...
- CentOS6.5环境配置笔记
CentOS6.5环境配置笔记 一.概述 服务器系统重装,配置应用运行环境 CentOS6.5 x64 二.修改密码 重新设置登录密码 $passwd 或 $passwd root 三.配置端口号及防 ...
- 转: scala语言的简单入门 (IBM develop)
转: https://www.ibm.com/developerworks/cn/java/j-lo-funinscala2/
- 数据结构之---C语言实现图的数组(邻接矩阵)存储表示
//图的数组(邻接矩阵)存储表示 #include <stdio.h> #include <stdlib.h> #define MAX_VEX_NUM 50 typedef c ...