线程进程

进程线程

进程就是一个任务,拥有自己独立的内存空间,用于一个以上的线程。
线程:操作系统能够进行运算调度的最小单位。可以理解为轻量级的进程,每个进程启动后,会默认产生一个主线程,主线程可以创建多个子线程,一个进程内的线程可以共享部分资源。

一个任务就是一个进程,一个进程中至少有一个线程。
多线程和多进程执行方式是一样的,都是操作系统在多个线程之间快速切换,交替运行。
当然真正同时执行多线程想要多核CPU才能实现。
多任务的实现三种方法:
多进程模式
多线程模式
多进程+多线程模式

多进程:数据共享复杂,占用内存多,切换复杂,CPU利用率低。进程间互不影响。
多线程:数据共享,占用内存少,切换简单,CPU利用率高。一个线程挂掉将导致整个进程挂掉。

多进程

multiprocessing模块提供一个Process类来代表进程对象

from multiprocessing import Process
def func(name):
  print(name)

if __name__ == '__main__':
  p=Process(target=func,args=('test',)) //创建Process实例
  p.start() //启动
  p.join()  //等待子进程结束后再继续往下运行,通常用于进程间的同步
Poll

使用进程池创建大量子进程

from multiprocessing import Poll
def func(name):
  print(name)

if __name__ == '__main__':
  p=Pool(4)
  for i in range(5):
      p.apply_async(func,args=("test",))
  p.close() //不在继续添加新的Process
  p.join()

进程间通信

进程间通信是通过Queue、Pipes(管道)等实现的

from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()
多线程(多个线程并发的技术)

threading模块
启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。

import threading
def func():
  print(threading,current_thread().name)
 
t=threading.Thread(target=func,name="Func_name")
t.start()
t.join()

任何进程都会启动一个线程,为主线程,主线程又可以启动新的线程。

Lock

多线程与多进程最大的不同在于
多进程:同一个变量,各自有一份拷贝存在每个进程中,互不影响
多线程:所有变量都由所有线程共享,任何变量都可被任何线程修改,因此线程之间共享数据最大的危险在于多个线程同时修改一个变量。

为了确保数据安全,就需要使用线程锁,当一个线程执行时,该线程因为获得了锁,其他线程不能同时执行,直到锁被释放。

import threading
balance =0   //共享的数据
lock=threading.Lock()

def change_it(n):
   global balance
   balance = balance + n
   balance = balance - n

def func(n):
    for i in range(100):
        lock.acquire()
        try:
              change_it(n)
        finally:
              lock.release()
 t1=threading.Thread(target=func,args=(5,))
 t2=threading.Thread(target=func,args=(5,))

t1.start()
t2.start()
t1.join()
t2.join()
进程 vs. 线程

多进程优点:稳定性高,一个进程奔溃了,不影响主进程和其他子进程,当然主进程挂了,所有进程就全挂了。
缺点:代价大,操作系统能同时运行的进程数也是有限的。
多线程优点:比多进程快一点,但是也快不到哪去
缺点:任何一个线程挂点都可能造成整个进程的奔溃,因为所有线程共享进程的内存。

异步IO

CPU的速度远远快于磁盘、网络。在一个线程中,CPU执行代码速度极快,一旦遇到IO操作,如读写文件,发送网络数据时,就需要等待IO操作完成,才能继续执行下一步操作。这种情况称为异步IO。
在IO操作中,如果当前线程被挂起,而其他需要CPU执行的代码就无法被当前线程执行。
因为一个IO操作就阻塞了当前线程,导致其他代码无法执行,所以我们使用多进程多线程来并发执行代码。
多进程(线程)虽然解决了并发问题,但系统不能无上限增加线程。
当代码需要执行一个耗时操作时,他只发出IO指令,并不等待IO结果,然后就去执行其他代码了。一段时间后,当IO返回结果时,再通知CPU进行处理。

线程池

一个线程的运行时间可以分为3个部分:线程的启动时间、线程的运行时间和线程的销毁时间。如果线程不能被重复利用,必增加系统的相应时间,降低了效率。
使用线程池:
线程预先被创建然后放入到线程池中,同时处理完当前任务之后并不会被销毁而是被安排处理下一个任务,避免多次创建线程,带来更好的性能和系统的稳定。

为什么使用线程池与优势

1.减少了创建和销毁线程的次数,每个工作线程都可能被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存。

GIL

全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序时会霸占python解释器(即加了一把锁),使该进程内的其他线程无法运行,等该线程运行完成后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁打开,其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时运行。

装饰器

他可以让函数在不做任何变动的情况下增加额外的功能,返回值也是一个函数对象,插入日志,性能测试,事务处理,缓存和权限验证。

多线程

python并不支持真正意义上的多线程,python提供了多线程包,python中有一个GIL ,它确保你的代码永远只有一个线程在执行。经过GIL处理,会增加执行的开销,如果你的代码是IO密集型,多线程可以明显提高效率,相反你的代码是CPU密集型的多线程大部分是鸡肋。

os模块文件的操作

os.remove()
os.rename()
os.mkdir()
os.chmod()

操作系统的设计

1.以多进程形式,允许多个任务同时进行
2.以多线程形式,允许单个任务分成不同的部分运行
3.提供协调机制,一方面防止进程间和线程之间的冲突,另一方面允许进程之间和线程之间资源的共享

什么时候用多线程 什么时候用多进程

1.频繁创建销毁,需要进行大量计算的,多核分布的
2.多机分布

线程安全与不安全

加锁的就是安全的,不加锁的就是不安全的

你可能感兴趣的:(线程进程)