Python网络编程之进程与线程(一)

网络编程

假如有俩程序,第一个程序执行到一半,需要I/O操作,这时候需要切换到第二个程序,“切换”引发的问题涉及到状态的保存,状态的恢复,加上俩程序所需要的系统资源(如内存,硬盘,磁盘等)是不一样的。自然而然就需要一个东西区记录俩程序分别需要的资源,怎么识别俩程序等等。所以就有了一个叫进程的抽象。

进程

进程定义:
进程就是一个程序在一个数据集上的一次动态执行过程(抽象的概念)。
进程一般由程序,数据集,进程控制块三部分组成。
我们编写的程序用来描述进程要完成哪些功能以及如何完成。
数据集则是程序在执行过程中所需要使用的资源。
进程控制块用来记录进程的外部特性,描述进程的执行变换过程,系统可以利用他来控制和管理进程,他是系统感知进程存在的唯一标志。

线程

线程定义:
线程,有时被称为轻量进程,是程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位。

进程与线程俩者的关系:
1.一个程序至少一个进程,一个进程至少一个线程。(进程可以理解成线程的一个容器)
2.进程在执行过程拥有独立的内存单元,而多个线程共享内存,从而极大 地提高了程序的运行效率。
3.进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体,是CPU调度和分配的基本单位,他是比进程更小的能独立运行的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。
4.线程的执行过程与进程还是有区别的。每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。但是线程不能独立执行的,必须依存在应用程序中,应用程序提供多个线程执行控制。
5.进程是最小的资源单位,线程最小的执行单位。

多线程的简单创建

例如:

import threading
import time

def Foo(num):
    print('hello %d'%num)
    time.sleep(3)

if __name__ == '__main__':
    t1 = threading.Thread(target=Foo,args=(10,))
    t1.start()

    t2 = threading.Thread(target=Foo,args=(9,))
    t2.start()

    print('over ....')

执行结果同时出现:
hello 10
hello 9
over ….
停顿3秒后程序结束

多线程的join方法:

import threading
import time

def Foo():
    print('Foo开始于 %s'%time.ctime())
    time.sleep(3)
    print('Foo结束于 %s' % time.ctime())

def Foo2():
    print('Foo2开始于 %s'%time.ctime())
    time.sleep(5)
    print('Foo2结束于 %s' % time.ctime())

if __name__ == '__main__':
    t1 = threading.Thread(target=Foo)
    t2 = threading.Thread(target=Foo2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print('over ....')

执行结果是:
Foo开始于 Sun Aug 19 12:42:17 2018
Foo2开始于 Sun Aug 19 12:42:17 2018
Foo结束于 Sun Aug 19 12:42:20 2018
Foo2结束于 Sun Aug 19 12:42:22 2018
over ….

换下:

import threading
import time

def Foo():
    print('Foo开始于 %s'%time.ctime())
    time.sleep(3)
    print('Foo结束于 %s' % time.ctime())

def Foo2():
    print('Foo2开始于 %s'%time.ctime())
    time.sleep(5)
    print('Foo2结束于 %s' % time.ctime())

if __name__ == '__main__':
    t1 = threading.Thread(target=Foo)
    t2 = threading.Thread(target=Foo2)
    t1.start()
    t2.start()
    t1.join()
    # t2.join()

    print('over ....')

这次把结果是:
Foo开始于 Sun Aug 19 12:42:55 2018
Foo2开始于 Sun Aug 19 12:42:55 2018
Foo结束于 Sun Aug 19 12:42:58 2018
over ….
Foo2结束于 Sun Aug 19 12:43:00 2018

再换下:

import threading
import time

def Foo():
    print('Foo开始于 %s'%time.ctime())
    time.sleep(3)
    print('Foo结束于 %s' % time.ctime())

def Foo2():
    print('Foo2开始于 %s'%time.ctime())
    time.sleep(5)
    print('Foo2结束于 %s' % time.ctime())

if __name__ == '__main__':
    t1 = threading.Thread(target=Foo)
    t2 = threading.Thread(target=Foo2)
    t1.start()
    t1.join()
    t2.start()
    t2.join()

    print('over ....')

执行结果是:
Foo开始于 Sun Aug 19 12:48:43 2018
Foo结束于 Sun Aug 19 12:48:46 2018
Foo2开始于 Sun Aug 19 12:48:46 2018
Foo2结束于 Sun Aug 19 12:48:51 2018
over ….

子进程调用join方法后,在子进程执行完,主进程才会进行,否则不会进程后面的代码。

守护线程setDaemon:
守护进程:
如果你设置一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。如果你的主线程在退出的时候,不用等待那些子线程完成,那就设置这些线程的daemon属性。即在线程开始(thread.start())之前,调用setDeamon()函数,设定线程的daemon标志。(thread.setDaemon(True))就表示这个线程“不重要”。
  如果你想等待子线程完成再退出,那就什么都不用做,或者显示地调用thread.setDaemon(False),设置daemon的值为false。新的子线程会继承父线程的daemon标志。整个Python会在所有的非守护线程退出后才会结束,即进程中没有非守护线程存在的时候才结束。
  

并发与并行

并发:是指系统具有处理多个任务(动作)的能力,同一时间段。
并行:是指系统具有同时处理多个任务(动作)的能力,同一时刻。
并行是并发的一个子集

同步与异步

同步:是所有的操作都做完,才返回给用户结果。即写完数据库之后,在相应用户,用户体验不好。
异步:不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好。
举列子:
打电话就是同步,发短信就是异步。
实体店买东西就是同步,网购就是异步。

阻塞与非阻塞

阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

同步,异步,阻塞,非阻塞的区别:
阻塞与非阻塞值得是一种可能出现的状态。而同步与异步是一种协作方式。
阻塞、非阻塞、多路IO复用,都是同步IO,异步必定是非阻塞的,所以不存在异步阻塞和异步非阻塞的说法。真正的异步IO需要CPU的深度参与。换句话说,只有用户线程在操作IO的时候根本不去考虑IO的执行全部都交给CPU去完成,而自己只等待一个完成信号的时候,才是真正的异步IO。所以,拉一个子线程去轮询、去死循环,或者使用select、poll、epool,都不是异步。

猜你喜欢

转载自blog.csdn.net/huang_yong_peng/article/details/81838006