线程进程

2019-07-09  本文已影响0人  上山走18398

多线程 多进程 协程的异同点

同步异步阻塞和非阻塞的概念

同步和异步关注的是消息通信机制:
是否等待返回结果,才去做另一件事情
同步在没有得到结果前,该调用就不返回,不开始新的步骤--阻塞式调用

回调 :双向调用模式,被调用方在接口被调用时也会调用对方的接口

异步调用: 类似消息或者时间机制,解决同步阻塞的问题,当接到通知或者事情时,调用某个通知接口
阻塞和非阻塞:
关注,程序在等待调用结果(消息,返回值)的状态,能不能干别的事情,是否挂起


实现你为某个事件(Event)所绑定(Binding)的方法(Method)。

计算密集型任务和IO密集型任务

计算密集型任务:CPU资源消耗异常大

IO密集型任务: 网络、磁盘IO任务,CPU消耗少(IO速度远低于CPU和内存的速度),99%时间花在IO上,代码量最少的语言优势大


异步IO: 单进程的异步编程模型为协程

  计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。
  这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,
  所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。

计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。

第二种任务的类型是IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。
对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。
常见的大部分任务都是IO密集型任务,比如Web应用。IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。
对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。

分布式编程:

在Thread和Process中,应当优选Process,因为Process更稳定,
而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。   


Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。
一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信。
由于managers模块封装很好,不必了解网络通信的细节,就可以很容易地编写分布式多进程程序。

同步原语

锁
信号量:
    它是一个计数器,当资源消耗时递减,当资源释放时递增

进程、线程

线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
进程:程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行 ,CPU调度

状态:
Running  进程占用处理器资源
Ready   (已获得除处理器外的所需资源) 
Blocked 进程由于等待I/O操作或进程同步等条件而暂停运行---当其他程序获得锁后,其他程序blocked住
New
Exit

多线程start后,可能的状态 run blocked->run...
产生blocked的原因:
sleep I/O操作 等待某个条件的改变

alive : run + blocked
not alive : new dead



操作系统中多个进程的并发执行是通过调度与超时两种转换间的循环,
或调度、等待事件和事件出现三种转换间的循环来描述的

线程:

线程锁:共享数据时,保证数据的正确性,其他线程blocked

------------------------
lock = threading.Lock() //生成全局锁 

lock.acquire()
... #共享数据
lock.release()
------------------------
Python解释器帮你自动定期进行内存回收(共享数据问题 ,GIL)
Python中由于全局锁(GIL)的存在导致多线程并不能利用多核

线程和进程/阻塞和挂起:

继承的原理

class MyThread(threading.Thread):
  def __init__(self,num):
      threading.Thread.__init__(self)
      self.num = num


在python中继承中的一些特点:

1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。有别于C#

2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)

协程

异步? 一个线程运行? 不用锁? 不用线程切换?
多进程+协程?

yield

gevent  python2
asyncio Python3.3以上

Python 库使用

thread  模块
thread.allocate_lock()
acquire()/release()
thread 不支持守护进程,主线程退出,所有子线程都退出



threading :支持守护线程



threads=[]
t=thrading.Thread(target=loop,args=(i,loops[i]))
threads.append(t)

thread[i].setDaemon()   ????? //守护线程,必须在start() 方法调用之前设置
// 通过将它们设置为守护线程,您可以让它们运行并忘记它们(监控事件?),当您的程序退出时,任何守护线程都会自动终止。打开的资源可能无法正确释放--信号机制
前后台程序,当别人都kill ,它也被kill ,如监控线程,当非守护线程都结束时,它也相当于没有作用了
Python中由于全局锁(GIL)的存在导致多线程并不能利用多核

thread[i].start() //开始线程




thread[i].join  //等待所有结束线程,父线程一直被阻塞

class ThreadFunc(object):
    
    def __init__(self,func,agrs,name="")
        self.name=name
        self.func=func
        self.args=args
    def __call__(self):
        apply(self.func,self.args)
        

apply(func,[,args[,kwargs]])函数用于当函数参数已经存在于一个元祖或字典中时,间接地调用函数

Timer 计时器

Events

event = threading.Event()

#一个客户线程可以等待设置的标志
event.wait()

#一个服务器线程可以设置或重置它
event.set()
event.clear()

Condition :一个线程等待另一个线程满足特定的条件

multiprocessing进程

multiprocessing.Process()
提供threading包中没有的IPC(比如Pipe和Queue)
队列管道是参数

multiprocessing.Pipe()
multiprocessing.Process(tartger=function,args=(pipe[i]))

生产者-消费者问题和Queue/queue模块

Queue模块的类

创建:
Queue(maxsize=0)  #创建一个先进先出的队列,最大值为何时阻塞

LifoQueue(maxsize=0) #创建一个后入先出的队列

PriorityQueue #优先级队列

异常:
Empty 空队列调用get*()方法抛出异常
Full  满队列调用put*()抛出异常

对象方法:
qsize()     大小
empty()     返回boolean
full()    返回boolean
put(item,block=True,timeout=None)
get(block=True,timeout=None)


#outputwork
queue.get

#inputwork
queue.put

线程之间通信机制,加入队列的时间不固定
multiprocessing.Lock()
multiprocessing.Queue()
multiprocessing.Process(tartger=function,args=(queue,lock))


上一篇 下一篇

猜你喜欢

热点阅读