进程与线程,并发与并行简单理解

2020-08-20  本文已影响0人  梧叶已秋声

这里不管进程与线程的概念,先看看进程与线程的使用。
现有代码如下,内含加法和减法函数,程序运行时按顺序调用加法和减法函数。

public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private int mInt1 = 10;
    private int mInt2 = 5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG,"add result " + add(mInt1,mInt2));
        Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));

    }

    private int add(int int1,int int2){
        for (int i = 0 ; i < 500 ; i ++){
            Log.d(TAG, "inner add " + i);
        }
        return (int1 + int2);
    }

    private int subtract(int int1,int int2){
        for (int i = 0 ; i < 500 ; i ++){
            Log.d(TAG, "inner subtract " + i);
        }
        return (int1 - int2);
    }

}

运行程序(即打开app)后如下所示。

2020-08-17 16:16:50.620 11449-11449/com.example.myapplication D/MainActivity: inner add 0
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 1
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 2
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 3
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 4
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 5
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 6
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 7
............................
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: add result 15
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 0
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 1
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 2
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 3
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 4
............................
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 494
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 495
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 496
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 497
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 498
2020-08-17 16:16:50.652 11449-11449/com.example.myapplication D/MainActivity: inner subtract 499
2020-08-17 16:16:50.652 11449-11449/com.example.myapplication D/MainActivity: subtract result 5

运行时间从16:16:50.62016:16:50.652,所需时间为0.032s。

现将程序简单修改,引入线程。

public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private int mInt1 = 10;
    private int mInt2 = 5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG,"add result " + add(mInt1,mInt2));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
            }
        }).start();
    }

    private int add(int int1,int int2){
        for (int i = 0 ; i < 500 ; i ++){
            Log.d(TAG, "inner add " + i);
        }
        return (int1 + int2);
    }

    private int subtract(int int1,int int2){
        for (int i = 0 ; i < 500 ; i ++){
            Log.d(TAG, "inner subtract " + i);
        }
        return (int1 - int2);
    }

  }

最后log如下所示(不同设备可能运行结果略微不一样,但是总归是轮流调用add和subtract函数)。

2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 0
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 1
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 2
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 3
2020-08-17 16:21:28.546 11828-11848/com.example.myapplication D/MainActivity: inner subtract 0
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 4
2020-08-17 16:21:28.546 11828-11848/com.example.myapplication D/MainActivity: inner subtract 1
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 5
...................................................
2020-08-17 16:21:28.559 11828-11847/com.example.myapplication D/MainActivity: inner add 498
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 496
2020-08-17 16:21:28.559 11828-11847/com.example.myapplication D/MainActivity: inner add 499
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 497
2020-08-17 16:21:28.559 11828-11847/com.example.myapplication D/MainActivity: add result 15
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 498
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 499
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: subtract result 5

运行时间从16:21:28.546到16:21:28.559,所需时间为0.013s。

由此可以看出,在输出同样的日志的情况下,引入线程后,耗时减少了。

而所谓进程,是程序的一次执行,这里可以理解为app的一次打开,即一次执行。
进程通常由程序、数据和进程控制块(Process Control Block,PCB)组成。
1.进程控制块。进程控制块是进程存在的唯一标志。

《软件设计师教程》

这里我只看看进程标识符。
进程标识符就是PID,每个应用在打开后,系统会给app分配一个标识符。

cmd进入控制台。

adb shell
ps 
image.png

显示当前所有进程,打开app后,输入ps |grep + 包名。

ps |grep com.example
u0_a119   29441 759   1678764 45676 SyS_epoll_ 0000000000 S com.example.myapplication

出处:Android 查看进程ID(PID)比较进程优先级
各列参数意义:
USER 进程当前用户;
PID Process ID,进程ID;
PPID Process Parent ID,进程的父进程ID;
VSIZE Virtual Size,进程的虚拟内存大小;
RSS Resident Set Size,实际驻留”在内存中”的内存大小;
WCHAN 休眠进程在内核中的地址;
PC Program Counter;
NAME 进程名;

2.程序
程序部分描述了进程需要完成的功能。我这里的demo就是加减数据的功能。
3.数据
数据部分包括程序执行时所需的数据及工作区。
这里涉及到程序执行时数据的存储。
一个可执行文件运行起来的话它就变成了进程,然后系统会给进程分配一个4G大小的虚拟地址空间。其中前3G内存是用户空间,最后1G是内核空间。所有的进程有各自的用户空间,但所有的进程都共享一个内核空间。

https://blog.csdn.net/czc1997/article/details/81159126

线程:

出处:《软件设计师教程》
传统的进程有两个基本属性: 可拥有资源的独立单位;可独立调度和分配的基本单位。由于在进程的创建、撤销和切换中, 系统必须为之付出较大的时空开销, 因此在系统中设置的进程数目不宜过多, 进程切换的频率不宜太高, 这就限制了并发程度的提高。引入线程后, 将传统进程的两个基本属性分开,线程作为调度和分配的基本单位,进程作为独立分配资源的单位。用户可以通过创建线程来完成任务, 以减少程序并发执行时付出的时空开销。

进程与线程的定义为:

线程作为调度和分配的基本单位,进程作为独立分配资源的单位。用户可以通过创建线程来完成任务, 以减少程序并发执行时付出的时空开销。

现在来看并发与并行。

并发(concurrency)和并行(parallelism)的区别
并发性(concurrency),又称共行性,是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。
并行(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。

将代码稍微修改,执行减法之前先休眠。

        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG,"add result " + add(mInt1,mInt2));
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.currentThread().sleep(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
            }
        }).start();
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 0
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 1
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 2
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 3
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 4
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 5
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 6
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 7
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 8
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 9
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 10
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 11
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 12
................................
2020-08-17 16:41:31.669 14006-14032/com.example.myapplication D/MainActivity: inner add 49
2020-08-17 16:41:31.669 14006-14033/com.example.myapplication D/MainActivity: inner subtract 0
2020-08-17 16:41:31.669 14006-14032/com.example.myapplication D/MainActivity: inner add 50
2020-08-17 16:41:31.669 14006-14033/com.example.myapplication D/MainActivity: inner subtract 1
2020-08-17 16:41:31.669 14006-14032/com.example.myapplication D/MainActivity: inner add 51
2020-08-17 16:41:31.669 14006-14033/com.example.myapplication D/MainActivity: inner subtract 2
................................

2020-08-17 16:41:31.682 14006-14032/com.example.myapplication D/MainActivity: inner add 499
2020-08-17 16:41:31.682 14006-14033/com.example.myapplication D/MainActivity: inner subtract 436
2020-08-17 16:41:31.682 14006-14032/com.example.myapplication D/MainActivity: add result 15
2020-08-17 16:41:31.682 14006-14033/com.example.myapplication D/MainActivity: inner subtract 437
2020-08-17 16:41:31.682 14006-14033/com.example.myapplication D/MainActivity: inner subtract 438
................................
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 496
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 497
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 498
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 499
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: subtract result 5

由于执行加法和减法函数的开始时间不同,16:41:31.668开始打印加法函数中的log,16:41:31.669开始打印减法函数中的log,并且,到16:41:31.669时加函数并未完成,因此此时程序是并发执行,而不是并行执行。
时间轴如下所示。

image.png

如果没有使用延时的情况下,也就是代码如下的情况下。


        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG,"add result " + add(mInt1,mInt2));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
            }
        }).start();
    }

时间轴如下所示。


image.png

log打印开始时间是同一时间,并且同时打印log,因此是程序是并行执行,并且也是并发执行

参考链接:
并发(concurrency)和并行(parallelism)的区别
《软件设计师教程》
Android 查看进程ID(PID)比较进程优先级

上一篇 下一篇

猜你喜欢

热点阅读