Linux系统编程学习笔记

PDB的常用的调试命令:

程序先写完的情况的调用方式:

1、 python3  -m pdb test.py

 #断点的过程  b 7     ## 后面的数字是 行数

 ## = 清楚断点的时候   clear 7  ## 后面的是数字行数

2、其他的一些指令

  PyCharm,常用的IDE。

3、r ----> return   快速执行到函数的最后一行

 4、还有一种交互式的调用方式

5、 服务器不停止的情况下,用日志调试法。

  1. 第三个视频 pep8规则

1、

2、函数和类 之间一般用两个空格隔绝爱,类与类之间一个空格

3、Python3 默认 UTF-8,不应有编码声明。

4、想在一行代码里放两条语句,用分号隔开。

  1. 第五个视频  多任务的理解

1、单核CPU可以同时运行好多的程序的原因是: 利用的时间片轮转、优先级调度。

2、  并行

        并发       两个词汇的理解,一般我们的电脑都是并发的类型。

进程的创建-fork

1、 import  os

       ret = os.fork()       # linux中才有的东西

2、 

   如图所示就会完成, if 和else 里面的内容一起执行。

3、父进程创建子进程,但是谁先执行还不一定        

4、 ret 这个值是多少?    创建一个子进程,自己本身是一个大于0的值,另一个子进程等于0

      用 cat  加上代码程序.py   就可以在命令行查看代码

os.getpid()  获取自己的PID,,os.ppid()-- 获取自己父亲的PID                                                    

08父子进程的先后顺序

1、只要主进程执行完毕,就可以打印系统提示

    for example:   多任务,加快程序的运行

09全局变量在多个子进程中 不共享

1、 全局变量在一个进程中修改,在另一个进程没有影响

10多次fork问题

1、  fork炸弹:

         while  true:

                os.fork()       # 不要随便执行这个代码,一下子就崩溃

12 Process 创建进程 --- 跨平台的写法

1、以后写创建子进程的方式,不用fork的方式,用这种可以跨平台的方式来写

13 主进程等待Process里的子进程先结束

1、主进程要等待着 所有的子进程先结束才会over,,儿子孙子都运行完之后才能自己结束!0

14 join 子进程

1、join()⽅法可以等待⼦进程结束后再继续往下运⾏, 通常⽤于进程间的同

  for example:

 等待 子进程结束以后在去打印 “----main----” 这个主进程的东西

   主进程等待着 子进程的运行,一直在 p.join( ) 这里等待着,称为 堵塞 状态。

    ## 函数说明里面带有 中括号的,就是意味着 可写可不写的状态。

    join([ timeout])    timeout : 等待的最长的时间。

2、p.terminate   不管任务是否完成,立即终止

15  Process 子进程

1、计算运行程序所花的时间:

      import  time

      time.time()    ##  调用time里面的time()方法,通过两个时间相减就可以得到程序运行所需要的时间。

2、

程序中,,当 定义一个是实际类后,执行 p.start() ,会首先进入 start()方法里面进行执行,这个方法里面蕴含着调用  run方法,调用run方法之后,创建的子进程就会 执行run()方法

    如果在后面给主程序加上两句代码如下:

      while(true)

             print("-----main-----")

             time.sleep(1)

    相应的子进程和主进程就会同时执行两个打印过程, 一个打印 -----1----   另一个打印 ----main----- 方法。

16  进程池   -- 非常简单的一种 创建 进程的方法

1、  第一点,先导入:   from  multiprocessing import  Pool

                                       import os,time,random

   po = Pool(3)  # 定义一个进程,最大的进程数是 3

10个任务交给3个小弟去做, 所以只有先安排的任务做完了,才会有新的进程进入到进程池里面。

 重点需要说的一点: pool.apply_async(worker,(i,))

    pool.close    # 关闭进程池,相当于 不能够再次添加新任务了

    pool.join()    #

17 创建 进程的总结

1、   ret = os.fork()    #  尽量不要用,非常底层

2、  Process (target = xxxx)

       p1.start()

   ## 通过创建子类来创建 进程

3、 创建进程池,,,推荐使用

    # 主进程一般用来等待,真正的任务一般都在子进程中执行

      pool = Pool (3)   # 经过压力测试,得出一个合适的值。

      pool.apply_async(xxxx)

18  堵塞式添加任务

1、

图中红色箭头的地方,实际上,当继续执行的时候, 打印出来一个数字,然后创建一个子进程,当去执行子进程的时候,主程序就会卡在原来的位置不变,等到上一个任务执行完之后才会继续添加新任务。  几乎不用的一种方式。

19  进程间的通信- Queue (  队列 )

1、对于队列来说是    先进先出

        还有就是  定义一个队列应该这么定义:    p = Queue(x)   # 里面的 x 代表队列的大小,如果不写的话,意味着你这个队列想要多大都可以,自己随意。

2、 常用的一些方法

     队列可以填充任何的东西,任何东西都是可以往里面添加的

3、q.get_nowait()

     q.put_nowait()     不需要等待,或者以另外一种方式告诉你  队列已经空了,或者已经满了不能存放其他数据了。

4、进程池中的Queue

     进程池中的通信和普通进程之间的通信大致是一样的,但是需要做两点

      (1)、导入一个模块   from multiprocessing import Manager, Queue

 换成 Manager 的形式!

(2)、 以下是两种 利用队列进行通信的对比

(3)进程池中的通信

进程与进程之间默认是没有联系的,,要想联系到一起,其中一种方法就是 队列。

二、多线程  (Linux系统编程)

1、使用Thread 完成多线程任务

   1、python 中的一个  Threading 模块,能够很好的实现多线程的任务。

           最简单的例子:      

 threading模块中的 Thread 函数和上一节课所学的  Process 模块类似,用法也类似,可以实现同时打印五句话。

进程是资源分配的单位,线程是CPU调度的单位。在同一个进程里面完成创建多个线程,进而进行运算,这样的方案能够在现有资源的基础上,实现更高的效率。

 绿色的称之为 主线程,当主线程运行到 Thread(target = test ),这句话是,就会创建一个额外的子线程(红颜色的箭头),子线程从哪里执行,实际上已经规定好了,就是从 test 开始执行。  主线程在这里其实只是执行了5次for循环,真正打印东西的是  主线程生成的5个子线程。

2、使用Thread子类完成创建多线程

1、多个线程执行一个函数的时候,各自之间不会有影响,各是各的。

2、创建线程的新办法:

 

 创建一个自己的类,以 Thread作为自己的基类,然后将自己要实现的东西放在 类里面的 run方法里面。  

    当后面,创造一个实例之后,执行 t.start() 时,在start方法里面有一个调用 run方法的隐藏,所以就会直接调用 run方法,进而直接执行 类里面的方法。

3、线程的执行顺序

1、

 当执行完创建线程任务时,这时候有6个线程等待着操作系统去调度,所以这时候谁先被执行呢? 执行顺序和你执行线程没有太大的关系,操作系统说了算!

4、线程共享全局变量

1、  进程: 不管全局变量还是局部变量,统统都是个人是个人的,互相之间没有影响。

        线程:  线程之间共享全局变量。

5、 线程共享全局变量的问题

 (视频出现了问题,播放不了,找一下其他地方的视频补上 )

1、   这种方式  可以解决   之间的通信。

        线程共享全局变量,就会有一些弊端存在!

      

6、 列表当作实参传递线程处理函数中

1、

  将一个列表当作是一个参数传递到函数里面的时候也是可以共享的, 多线程共享全局变量。

7、进程和线程的对比

1、

   为什么最后的结果不是 200w次呢?

   操作系统每一次只能执行一句程序,所以当一个程序还没运行完的时候,就已经被赶出来了,所以出现了很多的重叠,所以不是200w次。

8、避免全局变量被修改的方式

1、上面的例子修改的方式:

       第一种方法就是: 使用  sleep,让其中的一个进程进行执行,当执行完之后在继续执行下一个进程,这样就不会出现这种问题了。

2、

这种方案也非常不错,轮询的方式运行!

9、互斥锁

1、创建互斥锁

具体上锁:

threading.Lock(   )    # 里面有两个重要的参数,第一个 blocking 默认为 true:询问一下是否堵塞。

  第二个参数是, timeout ,设定一下运行的时间,默认为 -1,无限等待。

对于上面的代码出现的问题,用互斥锁来解决的方法:

优点: 当一个进程因为没有抢到上锁而停滞的时候,它不占用CPU,所以相对来说,效率就会变高。

10、大家遇到的问题 (还没有看,明天继续看!)

1、 将上锁放在 for循环里面,这样的话,导致一种现象就是, 每一次执行for循环的时候,两个循环里面都在竞争上锁,降低效率。

 什么时候加锁?  上锁的代码越少越好。 为什么不是100w,因为每次都在抢着上锁,所以不确定执行的次数。

11、多线程使用非共享变量

1、 threading 模块当中的 current_thread()方法 的名字就是当前线程里面的名字。

2、虽然两个线程都到同一个函数里面去执行,但是个人是个人的变量,互相不影响。

     去看一下文档里面的代码,然后反思一下。

12、死锁以及解决办法

1、看门狗 的原理,,添加一个变量。

13、同步的理解已经使用

1、同步就是协同步调,按预定的先后次序进行运行。 异步: 不确定先后的顺序。

2、用 互斥锁实现“同步” 的方法:

14、生产者与消费者来解决耦合问题

                 解耦在写代码的过程中非常重要!

1、 第一个导入队列模块:(队列: 先进先出 )

      python3 中应该这么写:  from queue import Queue 

      python2 中应该这么写:  from Queue import Queue

2、 线程中的队列创建方式:  queue = Queue( )

              ----- 队列的基本操作: queue.put()   queue.get()    queue.qsize()   queue.put_nowait()

      生产者与消费者之间的关系的一个完整的代码形式:

 队列就是用来 给 生产者和消费者之间解耦用的

15、ThreadLocal对象在线程中的使用

1、使用全局字典的方法

   这种方案可以实现,但是非常的费劲,所以下一种方法应运而生

2、ThreadLocal 方法

    当两个线程都需要对全局变量进行操作的时候,就可以联想这个ThreadLocal 方法的使用。

         对属性设置一个值,这一点需要自己课下好好的回顾一下

 

15、异步的实现

1、实现代码好好看看

异步: 就是当我正在做着某件事情的时候,突然通知我去做其他的事情, 这种情况叫做 异步。

    上述代码的原理:

     1)、 主进程一直在睡觉,当 子进程执行完毕的时候,主进程醒来,直接去执行 test2 ,, 子进程在结束的时候,会传递一个  “hahaha” 给test2(主进程), 这种情况叫做 异步。

      2)、 定义一个 线程池,,  然后调用   pool.apply_async( func = test,callback = test2): 这句代码的解释是:   前面的 func = test,就相当于直接写 一个 test,, 后面的 callback 意思是 回调,主进程去干的事情。

16、GIL的问题 ---  全局解释器锁

1、 多进程的效率明显大于 多线程的效率, 对于单核来说没必要,但是对于多核来说 至关重要。

2、 如何解决这个问题呢?

       接下来首先需要了解一下的是, 如何在Ubuntu系统中写C语言程序:

        以后在开发的过程中,无论是从网上当下来一个 C语言程序还是其他的,首先都要去重视一下 read.me 文件,用代码  cat  read.me   就可以读出来该 C语言程序应该如何执行以及运行在什么环境下。 切记这一点!

     克服Python中死循环的问题:   死循环用C语言来写,这样能使得程序的执行效率达到很高的程度。

    

猜你喜欢

转载自blog.csdn.net/qq_18649781/article/details/85221514