美文网首页
进程与线程,并发与并行简单理解

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

作者: 梧叶已秋声 | 来源:发表于2020-08-20 09:36 被阅读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)比较进程优先级

    相关文章

      网友评论

          本文标题:进程与线程,并发与并行简单理解

          本文链接:https://www.haomeiwen.com/subject/sgvfjktx.html