协程 线程 进程 程序

协程 线程 进程 程序

Posted by AnAn on December 1, 2020

协程 线程 进程 程序

  • 协程 - 单线程内函数函数级跳转,python 可通过yield关键字 和 next(func)方法实现 也有greenlet gevent 等模块实现协程
    • 携程在函数间跳转时会保留现场上下文信息,然后跳转到另外一个函数,一般跳出跳回原函数时机由用户程序控制如 greenlet ,也
      可由模块通过算法判断跳出跳回时机 如gevent
  • 线程
    • 程序最小的执行的单位,一个程序可以有多个进程,并且每个进程可以有多个线程。拥有相同父进程的多个线程间共享一片内存,所
      以使用多线程时无需为资源共享设计方法,但需要考虑线程安全。
    • 多个线程在多核处理器上可以并行执行。
  • 进程
    • 一个程序可以创建多个进程,不同进程间资源隔离,所以如需共享资源,可以借助pip queue shareMemery socket等方法实现。多个进程
      可以在多CPU机器上并行执行。
  • 程序
    • 指含有指令和数据的文件
  • 使用时机
    • 三种方法用于对于程序内多模块在时序上有并行执行的需求的任务场景
    • 一般功能高度独立的程序推荐用多进程方法,因为使用多线程,一个没处理的错误会同进程的所有线程崩溃。
    • 对于高耦合性的模块,推荐使用多线程,因为多线程之间资源共享相对多进程较为简单,并且高耦合意味着要CPU频繁切换
      于多个线程,相比于多进程,多线程之间的切换开销要低。
    • 对于协程,一般用于单线程内,IO操作,网络请求操作等耗时,并且不需要CPU守护的程序操作的的切换,用此来提高速度。
    • 总之,一个程序可以有多个进程,一个进程可以有多个线程,一个线程可以在多个协程之间切换。

      java syncronized

  • 该关键字可以修饰 方法名 代码块
  • 如下,sFunc1的写法等加sFunc2的写法,func1的写法等价func2的写法。可见不论syncronized关键字放在什么位置,
    均可用syncronized(lock){代码块;}来等价描述,为了方便讨论,后边均以该种方式进行讨论。值的注意的是this 作为lock指的是
    当前实例作为临界资源,意思是类型相同的两个实例拥有不同临界资源。L1.class作为lock指的是将L1类作为临界资源,意思是
    L1的所有实例共享同一个临界资源。
    package com.wangwen;  
    public class L1  {  
        public static synchronized void sFunc1(){  
            System.out.println("im sFunc1");  
        }  
        public static void sFunc2(){  
            synchronized (L1.class){  
                System.out.println("im sFunc2");  
            }  
        }  
        public synchronized void func1(){  
            System.out.println("im func1");  
        }  
        public void func2() {  
            synchronized (this) {  
                System.out.println("im func2");  
            }  
        }  
    }  
    
  • 使用syncronized关键字目的是锁定临界资源,使得多个线程在并发运行时,对于拥有临界资源的线程运行,没有临界资源的线程阻塞。而对于线程而言,lock便是临界资源。
  • 如果一段程序没有syncronized修饰,则该线程判定其没有临界资源(即使程序内部使用了其他线程中修饰过的临界资源)。如下,虽然在s1方法和s2方法中均有使用成员lockResource,且s1方法将lockResource声明为
    临界资源,但是由于s2方法并没有用synchronized声明lockResource,所以线程b运行时判定lockResource为非临界资源,即不会阻塞s2方法的运行,造成不安全访问lockResource。OUTPUT为运行结果。问题出在s2为线程
    不安全的方法,修改方法为在s2中使用synchronized声明lockResource 为临界资源。
    package com.wangwen;  
        
    public class L2 {  
        byte[] lockResource = new byte[1];  
        public  void s1() throws InterruptedException {  
            synchronized(lockResource) {  
                for (int i = 0; i < 10; i++) {  
                    lockResource[0]=(byte) 1;  
                    System.out.println(Thread.currentThread()+" im s1 lockResource:"+lockResource[0]);  
                    Thread.sleep(200);  
                    L1.class.getClass();  
        
                }  
            }  
        }  
        public void s2() throws InterruptedException {  
            for (int i = 0; i < 10; i++) {  
                lockResource[0]=(byte) 2;  
                System.out.println(Thread.currentThread()+" im s2 lockResource:"+lockResource[0]);  
                Thread.sleep(200);  
            }  
        }  
        
        public static void main(String[] args) throws InterruptedException {  
            final L2 l = new L2();  
            Thread a=new Thread(()->{  
                try {  
                    l.s1();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
        
            },"Thread a");  
            Thread b=new Thread(()->{  
                try {  
                    l.s2();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            },"Thread b");  
            a.start();  
            b.start();  
            a.join();  
            b.join();  
        }  
    }  
    /*OUTPUT  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread b,5,main] im s2 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:1  
    Thread[Thread b,5,main] im s2 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:1  
    Thread[Thread b,5,main] im s2 lockResource:2  
    Thread[Thread b,5,main] im s2 lockResource:1  
    Thread[Thread a,5,main] im s1 lockResource:1  
    Thread[Thread b,5,main] im s2 lockResource:1  
    Thread[Thread a,5,main] im s1 lockResource:1  
    Thread[Thread b,5,main] im s2 lockResource:1  
    Thread[Thread a,5,main] im s1 lockResource:1  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread b,5,main] im s2 lockResource:2  
    Thread[Thread b,5,main] im s2 lockResource:1  
    Thread[Thread a,5,main] im s1 lockResource:1  
    Thread[Thread b,5,main] im s2 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread b,5,main] im s2 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:1  
    */  
    
  • 只要临界资源的地址不同,线程便会认为其是不同的临界资源,不论这些临界资源是不是包含关系。
  • 如下,逻辑上ss锁定的是类的所有实例,s1锁定的是当前实例,s2锁定的是当前实例,他们具有包含关系。上面这句话汉让人难以理解,并且
    有明显的错误。实际上ss方法是将L.class作为临界资源,所有实例共用同一个锁,即L.class。s1将当前实例作为临界资源,并且线程a,b,c使用的是
    同一个实例l。s2将L实例中的lockResource属性作为临界资源,线程a,b,c使用的是同一个l,lockResource属性在内存上自然也是相同的。所以严格的说只有临界资源l和lockResource是包含关系。
    但是对于线程,将判定l和b是完全不同的两个临界资源,所以线程a,b,c可以并行。
    package com.wangwen;  
        
    public class L {  
        byte[] lockResource = new byte[1];  
        public static synchronized void ss() throws InterruptedException {  
            for (int i = 0; i < 5; i++) {  
                System.out.println(Thread.currentThread() + " im ss");  
                Thread.sleep(200);  
        
            }  
        }  
        
        public synchronized void s1() throws InterruptedException {  
            for (int i = 0; i < 5; i++) {  
        
                System.out.println(Thread.currentThread() + " im s1");  
                Thread.sleep(200);  
        
            }  
        }  
        
        public void s2() throws InterruptedException {  
            synchronized (lockResource) {  
                for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread() + " im s2");  
                    Thread.sleep(200);  
                }  
            }  
        }  
        
        public static void main(String[] args) throws InterruptedException {  
            final L l = new L();  
            Thread a = new Thread(() -> {  
                try {  
                    l.s1();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
        
            }, "Thread a");  
            Thread b = new Thread(() -> {  
                try {  
                    l.s2();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }, "Thread b");  
            Thread c = new Thread(() -> {  
                try {  
                    L.ss();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }, "Thread c");  
            a.start();  
            b.start();  
            c.start();  
            a.join();  
            b.join();  
            c.join();  
        }  
    }  
    /*OUTPUT  
    Thread[Thread b,5,main] im s2  
    Thread[Thread c,5,main] im ss  
    Thread[Thread a,5,main] im s1  
    Thread[Thread b,5,main] im s2  
    Thread[Thread c,5,main] im ss  
    Thread[Thread a,5,main] im s1  
    Thread[Thread b,5,main] im s2  
    Thread[Thread c,5,main] im ss  
    Thread[Thread a,5,main] im s1  
    Thread[Thread b,5,main] im s2  
    Thread[Thread c,5,main] im ss  
    Thread[Thread a,5,main] im s1  
    Thread[Thread b,5,main] im s2  
    Thread[Thread a,5,main] im s1  
    Thread[Thread c,5,main] im ss  
    */  
    
  • 上边列举了3个反列,他们足以说明:线程是否会阻塞,由并行的多个线程是否声明的是同一个临界资源,下边写一个正例:
  • 正例中s1,s2,ss声明的是同一个临界资源,所以会阻塞运行。
    package com.wangwen;  
        
    public class L3 {  
        static byte[] lockResource = new byte[1];  
        public static void ss() throws InterruptedException {  
            synchronized(lockResource) {  
                lockResource[0]=(byte) 1;  
                for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread() + " im ss lockResource:"+lockResource[0]);  
                    Thread.sleep(200);  
                }  
            }  
        }  
        
        public void s1() throws InterruptedException {  
            synchronized(lockResource) {  
                lockResource[0]=(byte) 2;  
                for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread() + " im s1 lockResource:"+lockResource[0]);  
                    Thread.sleep(200);  
                }  
            }  
        }  
        
        public void s2() throws InterruptedException {  
            synchronized (lockResource) {  
                lockResource[0]=(byte) 3;  
                for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread() + " im s2 lockResource:"+lockResource[0]);  
                    Thread.sleep(200);  
                }  
            }  
        }  
        
        public static void main(String[] args) throws InterruptedException {  
            final L3 l = new L3();  
            Thread a = new Thread(() -> {  
                try {  
                    l.s1();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
        
            }, "Thread a");  
            Thread b = new Thread(() -> {  
                try {  
                    l.s2();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }, "Thread b");  
            Thread c = new Thread(() -> {  
                try {  
                    L3.ss();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }, "Thread c");  
            a.start();  
            b.start();  
            c.start();  
            a.join();  
            b.join();  
            c.join();  
        }  
    }  
    /*OUTPUT  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread a,5,main] im s1 lockResource:2  
    Thread[Thread c,5,main] im ss lockResource:1  
    Thread[Thread c,5,main] im ss lockResource:1  
    Thread[Thread c,5,main] im ss lockResource:1  
    Thread[Thread c,5,main] im ss lockResource:1  
    Thread[Thread c,5,main] im ss lockResource:1  
    Thread[Thread b,5,main] im s2 lockResource:3  
    Thread[Thread b,5,main] im s2 lockResource:3  
    Thread[Thread b,5,main] im s2 lockResource:3  
    Thread[Thread b,5,main] im s2 lockResource:3  
    Thread[Thread b,5,main] im s2 lockResource:3  
    */  
    

python 协程模块greenlet example

  from greenlet import greenlet  
  import time  
    
  def task_1():  
      while True:  
          print("--This is task 1!--")  
          g2.switch()  # 切换到g2中运行  
          time.sleep(0.5)  
    
  def task_2():  
      while True:  
          print("--This is task 2!--")  
          g1.switch()  # 切换到g1中运行  
          time.sleep(0.5)  
            
  if __name__ == "__main__":  
      g1 = greenlet(task_1)  # 定义greenlet对象  
      g2 = greenlet(task_2)  
        
      g1.switch()  # 切换到g1中运行   
  • python 协程模块gevent example
    ```python
    import gevent
    def task_1(num):
    for i in range(num):
    print(gevent.getcurrent(), i)
    gevent.sleep(1) # 模拟一个耗时操作,注意不能使用time模块的sleep
    def task_2(num):
    for i in range(num):
    print(gevent.getcurrent(), i)
    gevent.sleep(3)

def task_3(num):
for i in range(num):
print(gevent.getcurrent(), i)
gevent.sleep(6)

if name == “main”:
g1 = gevent.spawn(task_1, 5) # 创建协程
g2 = gevent.spawn(task_2, 5)
g3 = gevent.spawn(task_3, 5)

  g1.join()  # 等待协程运行完毕  
  g2.join()  
  g3.join()     ```