Android——多进程

2023-05-16

之前我们了解了 :
-----------------------------------Java——多线程浅析.
-----------------------------------Android——Handler详解
-----------------------------------Android——HandlerThread浅析
-----------------------------------Java——ThreadPool线程池

让我们继续看看Android多进程:

1. 概述

默认情况下,同一应用的所有组件均在相同的进程中运行,且大多数应用都不应改变这一点。但是,如果您发现需要控制某个组件所属的进程,则可在清单文件(AndroidMenifest)中执行此操作。

主要依靠android:process属性

  • 各类组件元素activity、service、receiver和 provider的清单文件条目均支持 android:process 属性,此属性可指定该组件应在哪个进程中运行。

  • 可以设置android:process属性,使每个组件均在各自的进程中运行,或者使某些组件共享一个进程,而其他组件则不共享

  • 也可设置 android:process,以便不同应用的组件在同一进程中运行,但前提是这些应用共享相同的 Linux 用户 ID 并使用相同的证书进行签署。

  • 此外,application 元素还支持 android:process 属性,用来设置适用于所有组件的默认值。

    • application类继承自 ContextWarpper 类,代表应用程序(即 Android App)的类,也属于Android中的一个系统组件
    • 每个Android App运行时,会首先自动创建Application 类并实例化 Application 对象,且只有一个。即 Application类 是单例模式(singleton)类
    • 也可通过 继承 Application 类自定义Application 类和实例
    • 即不同的组件(如Activity、Service)都可获得Application对象且都是同一个对象
    • Application 对象的生命周期是整个程序中最长的,即等于Android App的生命周期

当内存不足,而其他更急于为用户提供服务的进程又需要内存时,Android 可能会决定在某一时刻关闭某个进程。正因如此,系统会销毁在被终止进程中运行的应用组件。当这些组件需再次运行时,系统将为其重启进程。

2. 开启多进程模式

正常情况下,在android中多进程是指一个应用中存在多个进程的情况。在Android中使用多进程只有一种方法,就是在AndroidMenifest中指定android:process属性。如下所示:

<activity android:name=".FirstActivity"
		  android:process=":remote"/>
<activity android:name=".SecondActivity"
		  android:process="com.zchhh.LaunchMode:remote"/>		  

其中FirstActivity和SecondActivity分别指定了process属性,并且它们的属性值不同,这意味着当前又增加了两个新进程。

  • 假设当前包名为com.zchhh.LaunchMode,当FirstActivity启动时,系统会为它单独创建一个进程,进程名为"com.zchhh.LaunchMode:remote";
  • 当SecondActivity启动时,系统也会为它单独创建一个进程,进程名com.zchhh.LaunchMode.remote。

我们注意到FirstActivity和SecondActivity的android:process属性分别为:remote和com.zchhh.LaunchMode.remote,它们有什么区别呢?

首先:

  • :指要在当前进程名前面加上包名,这是一种简写方法
  • 对于FirstActivity来说它完整的进程名为com.zchhh.LaunchMode:remote
  • 对于SecondActivity中的声明方式,是一种完整的声明方式,不会附加包名

其次: 私有进程和全局进程

  • 进程名以“:”开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程当中
  • 不以“:”开头的进程属于全局进程,其他应用通过shareUID方式可以和它跑在同一个进程中
  • Android会为每个应用分配唯一的一个UID,具有相同UID的应用才能共享数据。

【注】:

  • (1)私有进程:android:process=":remote",以冒号开头,冒号后面的字符串原则上是可以随意指定的。如果我们的包名为“com.biyou.multiprocess”,则实际的进程名 为“com.biyou.multiprocess:remote”。这种设置形式表示该进程为当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。
  • (2)全局进程:进程名称不以“:”开头的进程都可以叫全局进程,如android:process=“com.secondProcess”,以小写字母开头,表示运行在一个以这个名字命名的全局进程中,其他应用通过设置相同的ShareUID可以和它跑在同一个进程。
  • (3)两个应用通过ShareUID运行在同一个进程中是有要求的,就是需要两个应用有相同的UID并且签名也要相同。

3. 多进程模式的运行机制

多进程运行起来并不单单指android:process属性即可,例如当我们创建SecondActivity时,它会运行在一个单独的进程中,android会为每一个应用或者进程分配一个独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这就导致在不同虚拟机中访问同一个类的对象会产生多个副本。

所有运行在不同进程中的四大组件,当它们之间需要通过内存来共享数据,都会共享失败,这也是多进程所带来的主要影响。正常情况下,四大组件也要通过一些中间层来共享数据,但是像这种简单地通过指定进程名来开启多线程都会无法正确运行。一般地,使用多进程会造成如下几方面的影响:

注意:

  • (1) 静态成员和单例模式完全失效。

  • (2) 线程同步机制完全消失:因为不是同一个内存,那么无论是锁对象还是全局类都无法保证线程同步,因为不同进程锁的不是同一个对象。

  • (3) SharePreference可靠性下降:SharePreference不支持两个进程同时执行写操作,因为会导致数据丢失,因为SharedPreferences底层是通过读写XML文件实现的,并发写显然会出现问题,甚至读/写多可能出问题。

  • (4) Application会多次创建:系统在创建进程的同时分配独立的虚拟机(即代表会多次创建Application),当一个组件运行在一个新的进程中,由于 系统要创建新的进程同时分配独立的虚拟机,因此就是一个启动应用的过程。既然重新启动则会创建新的Application。

  • (5)sharepreference数据可能会有误差(sharepreference不允许两个线程同时执行操作,其底层是通过XML文件读写完成)

IPC机制的介绍看这篇博文:Android——进程间通信方式.

4.进程生命周期与优先级

在大多数情况下,每个 Android 应用都在各自的 Linux 进程中运行。当需要运行应用的一些代码时,系统会为应用创建此进程,并使其保持运行,直到不再需要它且系统需要回收其内存以供其他应用使用。

应用进程的生命周期并不由应用本身直接控制,而是由系统综合多种因素来确定的,比如系统所知道的正在运行的应用部分、这些内容对用户的重要程度,以及系统中可用的总内存量。这是 Android 非常独特的一个基本功能。

应用开发者必须了解不同的应用组件(特别是 Activity、Service 和 BroadcastReceiver)对应用进程的生命周期有何影响。这些组件使用不当会导致系统在应用进程正执行重要任务时将它终止。

进程生命周期错误的一个常见示例:

  • 当 BroadcastReceiver 在其 BroadcastReceiver.onReceive() 方法中接收到一个 Intent 时,它会启动一个线程,然后从该函数返回
  • 一旦返回,则系统会认为 BroadcastReceiver 不再处于活动状态,因此不再需要其托管进程(除非其中有其他应用组件处于活动状态)
  • 因此,系统可能会随时终止进程以回收内存,这样会终止在进程中运行的衍生线程
  • 要解决这个问题,通常可以从 BroadcastReceiver 调度 JobService,这样系统就知道进程中还有处于活动状态的任务正在进行中。

为了确定在内存不足时应该终止哪些进程,Android 会根据每个进程中运行的组件以及这些组件的状态,将它们放入“重要性层次结构”。这些进程类型包括(按重要性排序):

看这篇博文:Android——进程优先级.

5.注意

再强调一遍使用方法:

Android中开启多进程只有一种方法,就是在AndroidManifest.xml中注册Service、Activity、Receiver、ContentProvider时指定android:process属性,例如:

<service
    android:name=".MyService"
    android:process=":remote">
</service>

<activity
    android:name=".MyActivity"
    android:process="com.shh.ipctest.remote2">
</activity>
  • :remote:以:开头是一种简写,系统会在当前进程名前附件当前包名,完整的进程名为:com.shh.ipctest:remote,同时以:开头的进程属于当前应用的私有进程,其它应用的组件不能和它跑在同一进程。
  • com.shh.ipctest.remote2:这是完整的命名方式,为全局进程,不会附加包名,其它应用如果和该进程的ShareUID、签名相同,则可以和它跑在同一个进程,实现数据共享。

几个注意的点:

5.1 Application的多次重建

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.processtest"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
 
    <application
        android:name="com.example.processtest.MyApplication"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">
        <activity
            android:name=".ProcessTestActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <service
            android:name=".ProcessTestService"
            android:process=":remote">
        </service>
    </application>
 
</manifest>

定义两个类:ProcessTestActivity和ProcessTestService,只是在Activity的onCreate方法中直接启动了该Service,同时,我们自定义了自己的Application类:

MyApplication :

public class MyApplication extends Application {
	public static final String TAG = "viclee";
	@Override
	public void onCreate() {
		super.onCreate();
		int pid = android.os.Process.myPid();
		Log.d(TAG, "MyApplication onCreate");
		Log.d(TAG, "MyApplication pid is " + pid);
	}
}

ProcessTestActivity :

public class ProcessTestActivity extends Activity {
	public final static String TAG = "viclee";
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_process_test);
 
		Log.i(TAG, "ProcessTestActivity onCreate");
		this.startService(new Intent(this, ProcessTestService.class));
	}
}

ProcessTestService :

public class ProcessTestService extends Service {
	public static final String TAG = "viclee";
 
	@Override
	public void onCreate() {
		Log.i(TAG, "ProcessTestService onCreate");
	}
 
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
 
}

执行上面这段代码,查看打印信息:

MyApplication onCreate
MyApplication pid is 6371
ProcessTestActivity onCreate
MyApplication onCreate
MyApplication pid is 6399
ProcessTestService onCreate

MyApplication的onCreate方法调用了两次,分别是在启动ProcessTestActivity和ProcessTestService的时候,且pid也不相同

  • Application的onCreate方法中做一些全局的初始化操作,它被初始化多次是完全没有必要的
  • 出现这种情况,是由于即使是通过指定process属性启动新进程的情况下,系统也会新建一个独立的虚拟机,自然需要重新初始化一遍Application

怎么来解决这个问题呢?

思路1: 通过在自定义的Application中通过进程名来区分当前是哪个进程,然后单独进行相应的逻辑处理。

public class MyApplication extends Application {
	public static final String TAG = "viclee";
 
	@Override
	public void onCreate() {
		super.onCreate();
		int pid = android.os.Process.myPid();
		Log.d(TAG, "MyApplication onCreate");
		Log.d(TAG, "MyApplication pid is " + pid);
 
		ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
        if (runningApps != null && !runningApps.isEmpty()) {
            for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
                if (procInfo.pid == pid) {
                     if (procInfo.processName.equals("com.example.processtest")) {
                    	 Log.d(TAG, "process name is " + procInfo.processName);
                     } else if (procInfo.processName.equals("com.example.processtest:remote")) {
                    	 Log.d(TAG, "process name is " + procInfo.processName);
                     }
                }
            }
        }
	}
}

运行之后,查看Log信息,

MyApplication onCreate
MyApplication pid is 23918
process name is com.example.processtest
ProcessTestActivity onCreate
MyApplication onCreate
MyApplication pid is 6399
process name is com.example.processtest:remote
ProcessTestService onCreate

不同的进程执行了不同的代码逻辑,可以通过这种方式来区分不同的进程需要完成的初始化工作

思路2: 判断是否为主进程,只有主进程的时候才执行下面的操作

String processName = this.getProcessName();
 
//判断进程名,保证只有主进程运行
if (!TextUtils.isEmpty(processName) &&processName.equals(this.getPackageName())) {
    //在这里进行主进程初始化逻辑操作                          
    Log.i(">>>>>>","oncreate");
}

//获取进程名的方法,这个方法效率是比较好的:
 public static String getProcessName() {
        try {
            File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
            BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
            String processName = mBufferedReader.readLine().trim();
            mBufferedReader.close();
            return processName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

5.2 静态成员的失效

将之前定义的Activity和Service的代码进行简单的修改,代码如下:
ProcessTestActivity :

public class ProcessTestActivity extends Activity {
	public final static String TAG = "viclee";
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_process_test);
 
		Log.i(TAG, "ProcessTestActivity onCreate");
		this.startService(new Intent(this, ProcessTestService.class));
	}
}

新ProcessTestActivity :

public class ProcessTestActivity extends Activity {
	public final static String TAG = "viclee";
	public static boolean processFlag = false;
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_process_test);
 
		processFlag = true;
		Log.i(TAG, "ProcessTestActivity onCreate");
		this.startService(new Intent(this, ProcessTestService.class));
	}
}

ProcessTestService :

public class ProcessTestService extends Service {
	public static final String TAG = "viclee";
 
	@Override
	public void onCreate() {
		Log.i(TAG, "ProcessTestService onCreate");
	}
 
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
 
}

新ProcessTestService :

public class ProcessTestService extends Service {
	public static final String TAG = "viclee";
 
	@Override
	public void onCreate() {
		Log.i(TAG, "ProcessTestService onCreate");
		Log.i(TAG, "ProcessTestActivity.processFlag is " + ProcessTestActivity.processFlag);
	}
 
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
 
}

重新执行代码,打印Log

MyApplication onCreate
MyApplication pid is 18580
process name is com.example.processtest
ProcessTestActivity onCreate
MyApplication onCreate
MyApplication pid is 6399
process name is com.example.processtest:remote
ProcessTestService onCreate
ProcessTestActivity.processFlag is flase

在Activity中定义了一个标志processFlag并在onCreate中修改了它的值为true,然后启动Service,但是在Service中读到这个值却为false

照正常的逻辑,静态变量是可以在应用的所有地方共享的,但是设置了process属性后,产生了两个隔离的内存空间,一个内存空间里值的修改并不会影响到另外一个内存空间。

5.3 文件共享问题

多进程情况下会出现两个进程在同一时刻访问同一个数据库文件的情况。这就可能造成
 - 资源的竞争访问,导致诸如数据库损坏、数据丢失等。在多线程的情况下我们有锁机制控制资源的共享
 但是在多进程中比较难,虽然有文件锁、排队等机制,但是在Android里很难实现。解决办法就是多进程的时候不并发访问同一个文件,比如子进程涉及到操作数据库,就可以考虑调用主进程进行数据库的操作。

IPC机制的介绍看这篇博文:Android——进程间通信方式.

5.4 断点调试问题

多进程情况下,可以通过【Attach to Process】来绑定辅助进程进行调试
在这里插入图片描述

  • 但这样有一个问题就是,无法对辅助进程的onCreate方法进行调试
  • 只有在进程启动后才可以绑定进程进行调试,而辅助进程启动时执行onCreate方法只是一瞬间的事情
  • 等手动绑定完进程后,onCreate方法一般都已经执行完毕了,所以没法对onCreate方法进行调试

解决方法:

  • 在onCreate方法的首行加入以下代码即可
  • Debug.waitForDebugger方法会让手机进程保持阻塞状态,直到连上调试器后,才会继续执行后续的代码
Debug.waitForDebugger()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android——多进程 的相关文章

  • 2023安装archlinux笔记

    本文只是个笔记 xff0c 不是详细教程 xff0c 仅供参考 安装过程基本与 2021年vmware安装archlinux https blog csdn net lxyoucan article details 115226297 差不
  • 命令行临时关闭Hyper-V功能

    背景 安装VMware时有如下提示 xff1a 命令行关闭Hyper V功能 xff08 1 xff09 以管理员身份 xff08 win 43 x xff09 运行命令提示符 xff1b xff08 2 xff09 执行命令 xff1a
  • debian安装ssh服务

    安装 span class token function apt get span span class token function install span openssh server 安装完成以后 可以通过以下命令看到它们运行的进程
  • kitty 终端使用ssh

    我的主要终端软件就是使用kitty 但是在kitty中直接使用ssh时会有一些小问题 比如 xff1a ranger htop这类的在命令行中的 图形 软件打开会报错 Error opening terminal xterm kitty c
  • archlinux 罗技K380 F1-F12 功能键锁定

    在windows中罗技K380可以安装Logitech Options来实现这个Fn锁定功能 在linux中如何实现 Logitech Options中没有linux版本的 有开发者针对罗技的无线设备开发了Solaar软件 xff0c 可以
  • linux中的图形化UDP调试工具

    sokit freeware version 1 3 1 GPLv3 website https github com sinpolib sokit 这是一个TCP UDP数据包收发和传输工具 linux汉化 默认是英文版本的 xff0c
  • UDP内网穿透实战

    场景 最近的项目在做设备对接功能 设备对接协议使用的是UDP协议的 设备在客户那 因为设备太昂贵搬过来不现实 驻场开发又太麻烦了 所以就只能在远程桌面中开发 远程桌面中开发束手束脚的太麻烦了 所以想到了内网穿透 tcp协议的穿透经常玩 UD
  • sqlserver数据库备份与还原的几种方式

    在开发与运维的过程中 xff0c 数据的备份与还原是经常用到的 今天就说说我在sqlserver中常用的几个方法 xff0c 仅供参考 SQL Server Management Studio备份与还原 这种方法在开发环境中经常使用 xff
  • MySQL必知必会系列一:数据库老师没教过的数据库知识!!!

    在讲MySQL之前 xff0c 关于数据库有一个非常有意思的现象 xff1b 许多人认为MySQL或者Oracle等 xff0c 都等同于数据库 xff0c 这是不正确的 xff0c 准确来说它们是DBMS Database Managem
  • archlinux docker配置php5.3

    一直在维护一下10年前的老项目 xff0c 是基于php5 3开发的 一直在使用windows虚拟机在开发php5 3 最近就想尝试在archlinux主系统中开发 什么是php PHP 是一种广泛使用的通用脚本语言 xff0c 特别适合
  • IDEA中安装了lua插件后无法启动的解决办法

    现象 使用Idea编辑lua脚本 xff0c 根据提示安装了相关插件 安装完成后 xff0c 发现idea无法正常启动了 报错如下 2023 03 10 13 45 00 952 812 ERROR llij ide plugins Plu
  • Go 国内加速镜像

    Go 默认下载太慢了 xff0c 还老是timeout 有不有什么解决办法呢 xff1f linux 下面使用方法 启用 Go Modules 功能 go env w GO111MODULE 61 on 配置 GOPROXY 环境变量 xf
  • go打包成linux程序

    看到一个不错的的go开源项目 xff0c https github com antonmedv countdown 但是它只提供源码 xff0c 用起来不太方便 我在本地搭建了一下GO的运行环境 xff0c 每次运行程序都要 go run
  • Can‘t open /run/atd.pid to signal atd. No atd running?

    现象 echo 34 notify send 39 Stop it and go home now 39 39 Enough work for today 39 u critical 34 at now 13 27 33 warning c
  • 转换 nvarchar 值 ‘201201013201201013201201013‘ 时溢出了整数列

    现象 执行 select from lx stuinfo where lx stuinfo stunu 61 202202002 报错如下 xff1a 消息 248 xff0c 级别 16 xff0c 状态 1 xff0c 第 2 行 转换
  • RuoYi若依项目部署实战

    环境 OS Amazon Linux 2 x86 64Host c5 2xlargeKernel 5 10 173 154 642 amzn2 x86 64 mysql root密码为yourpasswd 64 2023 xff0c 数据库
  • linux C++ hello world

    我是Java程序员 xff0c 没怎么写过C 43 43 以前在windows下使用vs写过hello world 最近有个程序需要使用C 43 43 实现 我想在linux下写 xff0c 记录一下过程 安装gcc 查看gcc版本 gcc
  • mybatis foreach 批量删除 传两个参数

    需求 foreach中要传两个参数 xff0c 一个是id xff0c 一个是list 怎么传呢 xff1f 单list的情况 Mapper java span class token comment 批量删除 64 param teamL
  • ubuntu22.04 dlopen(): error loading libfuse.so.2

    报错如下 navicat16 premium cs AppImage dlopen error loading libfuse so 2 AppImages require FUSE to run You might still be ab
  • Android DataBinding在Activity、Fragment中的使用及数据共享

    本篇记录Activity Fragment使用DataBinding的不同方式 xff0c 以及Activity下的不同Fragment间的数据共享 开启DataBinding 首先我们要在app gradle中开启DataBinding

随机推荐

  • IDEA mybatis Mapper.xml报红的解决办法

    现象 在IDEA中已经配置好Database了 xff0c 但是打开mybatis的Mapper xml中的字段还是报红 如下 xff1a 随便不影响程序运行 xff0c 但是非常的不舒服 智能提示也不好用 解决办法 File gt Set
  • Windows 2008 R2 Server远程无法复制的解决办法

    结束进程rdpclip exe运行中重新运行rdpclip exe 两步完美解决 参考 https bbs huaweicloud com blogs 307039
  • WinScp密钥登录

    使用密码登录非常的方便 xff0c 但是有的客户的云服务器上是限定只能通过密钥登录 我一般使用命令行的scp命令就可以正常上传 xff0c 但是对于我一些同事来说 xff0c 就很不方便 生成密钥 这个不难 xff0c 可以参考我之前的文章
  • FileZilla密钥登录

    使用密码登录非常的方便 xff0c 但是有的客户的云服务器上是限定只能通过密钥登录 我一般使用命令行的scp命令就可以正常上传 xff0c 但是对于我一些同事来说 xff0c 就很不方便 生成密钥 这个不难 xff0c 可以参考我之前的文章
  • node js 设置淘宝源

    淘宝镜像源最新地址 span class token function npm span config span class token builtin class name set span registry https registry
  • 手推DNN,CNN池化层,卷积层反向传播

    反向传播算法是神经网络中用来学习的算法 xff0c 从网络的输出一直往输出方向计算梯度来更新网络参数 xff0c 达到学习的目的 xff0c 而因为其传播方向与网络的推理方向相反 xff0c 因此成为反向传播 神经网络有很多种 xff0c
  • 软件架构概念和面向服务的架构

    摘要 软件架构作为软件开发过程的一个重要组成部分 xff0c 有着各种各样的方法和路线图 xff0c 它们都有一些共同的原则 基于架构的方法作为控制系统构建和演化复杂性的一种手段得到了推广 引言 在计算机历史中 xff0c 软件变得越来越复
  • 初识强化学习,什么是强化学习?

    相信很多人都听过 机器学习 和 深度学习 但是听过 强化学习 的人可能没有那么多 那么 什么是强化学习呢 强化学习是机器学习的一个子领域 它可以随着时间的推移自动学习到最优的策略 在我们不断变化的纷繁复杂的世界里 从更广的角度来看 即使是单
  • 强化学习形式与关系

    在强化学习中有这么几个术语 智能体 Agent 环境 Environment 动作 Action 奖励 Reward 状态 State 有些地方称作观察 Observation 奖励 Reward 在强化学习中 奖励是一个标量 它是从环境中
  • 多层网络和反向传播笔记

    在我之前的博客中讲到了感知器 xff08 感知器 xff09 xff0c 它是用于线性可分模式分类的最简单的神经网络模型 xff0c 单个感知器只能表示线性的决策面 xff0c 而反向传播算法所学习的多层网络能够表示种类繁多的非线性曲面 对
  • 如何准备校招?

    秋招已经落尽尾声 xff0c 今天小牛想把自己的学习经验分享给大家 xff0c 避免大家多走弯路 1 首先需要确定自己想从事哪方面的工作 比如服务端开发 xff08 Java开发工程师 xff0c C 43 43 开发工程师 xff09 x
  • 在Kaggle手写数字数据集上使用Spark MLlib的朴素贝叶斯模型进行手写数字识别

    昨天我在Kaggle上下载了一份用于手写数字识别的数据集 xff0c 想通过最近学习到的一些方法来训练一个模型进行手写数字识别 这些数据集是从28 28像素大小的手写数字灰度图像中得来 xff0c 其中训练数据第一个元素是具体的手写数字 x
  • 在Kaggle手写数字数据集上使用Spark MLlib的RandomForest进行手写数字识别

    昨天我使用Spark MLlib的朴素贝叶斯进行手写数字识别 xff0c 准确率在0 83左右 xff0c 今天使用了RandomForest来训练模型 xff0c 并进行了参数调优 首先来说说RandomForest 训练分类器时使用到的
  • PyTorch模型保存与加载

    torch save xff1a 保存序列化的对象到磁盘 xff0c 使用了Python的pickle进行序列化 xff0c 模型 张量 所有对象的字典 torch load xff1a 使用了pickle的unpacking将pickle
  • Ubuntu18.04 上 安装微信(Deepin-Wechat)

    文章目录 一 安装Deepin Wine环境二 安装Deepin 版微信 微信什么时候支持在linux下的安装包啊 xff0c 我的天哪 xff0c 感觉受到了针对 xff0c 各位看官且看下图 xff1a 这里先作声明 xff1a 本文的
  • ROS机器人操作系统——ROS介绍

    AI is the new electricity 1 ROS发展史 本世纪开始 关于人工智能的研究进入了大发展阶段 包括全方位的具体的AI 例如斯坦福大学人工智能实验室STAIR Stanford Artificial Intellige
  • 如何快速学习一门计算机语言

    一 4步掌握一门计算机语言 1 学习语言的语法 xff0c 关键字 xff0c 以及基本的库 xff08 基础阶段 xff09 2 学习语言的第三方库和各个组件 xff08 OS xff0c 数据库 xff0c 网络 xff09 之间的连用
  • CentOs6.8离线安装svn,并设置自动更新

    CentOs6 8离线安装svn xff0c 并设置自动更新 离线安装所需依赖离线安装 GCC xff0c 如果系统已经有 GCC 了 xff0c 跳过这一步需要的 rpm 包安装顺序 离线安装 openssl需要的代码编译设置环境变量 离
  • Linux ping不通,连不上网的解决办法

    Linux ping不通 xff0c 连不上网的解决办法 可能原因是DNS没有配置好 方法一 xff1a 修改vi etc resolv conf 增加如下内容 xff1a nameserver 114 114 114 114 电信的DNS
  • Android——多进程

    之前我们了解了 Java 多线程浅析 Android Handler详解 Android HandlerThread浅析 Java ThreadPool线程池 让我们继续看看Android多进程 xff1a 1 概述 默认情况下 xff0c