WEEK9:Python 多线程、进程

  • 数据库操作与paramiko模块
    • 该模块基于ssh用于连接远程服务器并执行相关操作
      • SSHClient #用于连接远程服务器并执行基本命令
        • 基于用户名和密码连接
           1 #########执行命令
           2 import paramiko
           3 # 创建SSH对象
           4 ssh = paramiko.SSHClient()
           5 # 允许连接不在know_hosts(~/.ssh/known_hosts)文件中的主机
           6 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
           7 # 连接服务器
           8 ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', password='123')
           9 # 执行命令
          10 stdin, stdout, stderr = ssh.exec_command('df')
          11 # 获取命令结果
          12 result = stdout.read()
          13 # 关闭连接
          14 ssh.close()
          15 
          16 #########SSHClient封装Transport
          17 import paramiko
          18 transport = paramiko.Transport(('hostname', 22))
          19 transport.connect(username='wupeiqi', password='123')
          20 ssh = paramiko.SSHClient()
          21 ssh._transport = transport
          22 stdin, stdout, stderr = ssh.exec_command('df')
          23 print(stdout.read())
          24 transport.close()
        • 基于公钥密钥连接
           1 #########执行命令
           2 import paramiko
           3 private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
           4 # 创建SSH对象
           5 ssh = paramiko.SSHClient()
           6 # 允许连接不在know_hosts文件中的主机
           7 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
           8 # 连接服务器
           9 ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key)
          10 # 执行命令
          11 stdin, stdout, stderr = ssh.exec_command('df')
          12 # 获取命令结果
          13 result = stdout.read()
          14 # 关闭连接
          15 ssh.close()
          16 
          17 #########SSHClient 封装 Transport
          18 import paramiko
          19 private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
          20 transport = paramiko.Transport(('hostname', 22))
          21 transport.connect(username='wupeiqi', pkey=private_key)
          22 ssh = paramiko.SSHClient()
          23 ssh._transport = transport
          24 stdin, stdout, stderr = ssh.exec_command('df')
          25 transport.close()
          26 
          27 #########基于私钥字符串进行连接
          28 import paramiko
          29 from io import StringIO
          30 
          31 key_str = """-----BEGIN RSA PRIVATE KEY-----
          32 MIIEpQIBAAKCAQEAq7gLsqYArAFco02/55IgNg0r7NXOtEM3qXpb/dabJ5Uyky/8
          33 NEHhFiQ7deHIRIuTW5Zb0kD6h6EBbVlUMBmwJrC2oSzySLU1w+ZNfH0PE6W6fans
          34 H80whhuc/YgP+fjiO+VR/gFcqib8Rll5UfYzf5H8uuOnDeIXGCVgyHQSmt8if1+e
          35 7hn1MVO1Lrm9Fco8ABI7dyv8/ZEwoSfh2C9rGYgA58LT1FkBRkOePbHD43xNfAYC
          36 tfLvz6LErMnwdOW4sNMEWWAWv1fsTB35PAm5CazfKzmam9n5IQXhmUNcNvmaZtvP
          37 c4f4g59mdsaWNtNaY96UjOfx83Om86gmdkKcnwIDAQABAoIBAQCnDBGFJuv8aA7A
          38 ZkBLe+GN815JtOyye7lIS1n2I7En3oImoUWNaJEYwwJ8+LmjxMwDCtAkR0XwbvY+
          39 c+nsKPEtkjb3sAu6I148RmwWsGncSRqUaJrljOypaW9dS+GO4Ujjz3/lw1lrxSUh
          40 IqVc0E7kyRW8kP3QCaNBwArYteHreZFFp6XmtKMtXaEA3saJYILxaaXlYkoRi4k8
          41 S2/K8aw3ZMR4tDCOfB4o47JaeiA/e185RK3A+mLn9xTDhTdZqTQpv17/YRPcgmwz
          42 zu30fhVXQT/SuI0sO+bzCO4YGoEwoBX718AWhdLJFoFq1B7k2ZEzXTAtjEXQEWm6
          43 01ndU/jhAasdfasdasdfasdfa3eraszxqwefasdfadasdffsFIfAsjQb4HdkmHuC
          44 OeJrJOd+CYvdEeqJJNnF6AbHyYHIECkj0Qq1kEfLOEsqzd5nDbtkKBte6M1trbjl
          45 HtJ2Yb8w6o/q/6Sbj7wf/cW3LIYEdeVCjScozVcQ9R83ea05J+QOAr4nAoGBAMaq
          46 UzLJfLNWZ5Qosmir2oHStFlZpxspax/ln7DlWLW4wPB4YJalSVovF2Buo8hr8X65
          47 lnPiE41M+G0Z7icEXiFyDBFDCtzx0x/RmaBokLathrFtI81UCx4gQPLaSVNMlvQA
          48 539GsubSrO4LpHRNGg/weZ6EqQOXvHvkUkm2bDDJAoGATytFNxen6GtC0ZT3SRQM
          49 WYfasdf3xbtuykmnluiofasd2sfmjnljkt7khghmghdasSDFGQfgaFoKfaawoYeH
          50 C2XasVUsVviBn8kPSLSVBPX4JUfQmA6h8HsajeVahxN1U9e0nYJ0sYDQFUMTS2t8
          51 RT57+WK/0ONwTWHdu+KnaJECgYEAid/ta8LQC3p82iNAZkpWlGDSD2yb/8rH8NQg
          52 9tjEryFwrbMtfX9qn+8srx06B796U3OjifstjJQNmVI0qNlsJpQK8fPwVxRxbJS/
          53 pMbNICrf3sUa4sZgDOFfkeuSlgACh4cVIozDXlR59Z8Y3CoiW0uObEgvMDIfenAj
          54 98pl3ZkCgYEAj/UCSni0dwX4pnKNPm6LUgiS7QvIgM3H9piyt8aipQuzBi5LUKWw
          55 DlQC4Zb73nHgdREtQYYXTu7p27Bl0Gizz1sW2eSgxFU8eTh+ucfVwOXKAXKU5SeI
          56 +MbuBfUYQ4if2N/BXn47+/ecf3A4KgB37Le5SbLDddwCNxGlBzbpBa0=
          57 -----END RSA PRIVATE KEY-----"""
          58 
          59 private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
          60 transport = paramiko.Transport(('10.0.1.40', 22))
          61 transport.connect(username='wupeiqi', pkey=private_key)
          62 ssh = paramiko.SSHClient()
          63 ssh._transport = transport
          64 stdin, stdout, stderr = ssh.exec_command('df')
          65 result = stdout.read()
          66 transport.close()
          67 print(result)
      • SFTPClient #用于连接远程服务器并执行上传下载
        • 基于用户名和密码上传下载
          1 import paramiko
          2 transport = paramiko.Transport(('hostname',22))
          3 transport.connect(username='wupeiqi',password='123')
          4 sftp = paramiko.SFTPClient.from_transport(transport)
          5 # 将location.py 上传至服务器 /tmp/test.py
          6 sftp.put('/tmp/location.py', '/tmp/test.py')
          7 # 将remove_path 下载到本地 local_path
          8 sftp.get('remove_path', 'local_path')
          9 transport.close()
        • 基于公钥密钥上传下载
           1 import paramiko
           2 private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
           3 transport = paramiko.Transport(('hostname', 22))
           4 transport.connect(username='wupeiqi', pkey=private_key )
           5 sftp = paramiko.SFTPClient.from_transport(transport)
           6 # 将location.py 上传至服务器 /tmp/test.py
           7 sftp.put('/tmp/location.py', '/tmp/test.py')
           8 # 将remove_path 下载到本地 local_path
           9 sftp.get('remove_path', 'local_path')
          10 transport.close()
  • 进程与线程
    线程是操作系统能够进行运算调度的最小单位,他被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
    • 进程与线程的关系
      • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
      • 资源分配给进程,同一进程的所有线程共享该进程的所有资源
      • 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步
      • 处理机分给线程,即真正在处理机上运行的是线程
      • 线程是指进程内的一个执行单元,也是进程内的可调度实体
      • 两者均可并发执行
    • 进程与线程的区别
      • 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。线程是处理器调度的基本单位,但是进程不是
      • 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行
      • 拥有资源:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的,进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源
      • 地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间
      • 系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统的明显大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些。如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程
      • 执行过程:每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
    • 其他说明
      • 线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大的提高了程序运行效率。线程在执行过程中,每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,有应用程序提供多个线程执行控制。多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。
      • 线程执行开销小,但是不利于资源的管理和保护,线程适合在SMP机器(双CPU系统)上运行。进程执行开销大,但是能够很好的进行资源管理和保护,进程可以跨机器前移。
      • 何时使用多进程,何时使用多线程?对资源的管理和保护要求高,不限制开销和效率时,使用多进程。要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
    • 直接调用:
      同时启动50个线程,区分子线程和主线程
      守护线程即不重要的线程,主线程不等待守护线程,直接执行下面的线程。
       1 import threading
       2 import time
       3 
       4 def run(n):
       5     print("task ",n )
       6     time.sleep(2)
       7     print("task done",n,,threading.current_thread())
       8 
       9 start_time = time.time()
      10 t_objs = [] #存线程实例
      11 for i in range(50):
      12     t = threading.Thread(target=run,args=("t-%s" %i ,))
      t.setDaemon(True) #把当前线程设置为守护线程,必须在线程start之前设置
      13 t.start() 14 t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里 15 16 for t in t_objs: #循环线程实例列表,等待所有线程执行完毕 17 t.join() 18 19 print("----------all threads has finished...",threading.current_thread(),threading.active_count()) 20 print("cost:",time.time() - start_time)
    • 继承式调用
       1 import threading
       2 import time
       3 
       4 class MyThread(threading.Thread):
       5     def __init__(self,n,sleep_time):
       6         super(MyThread,self).__init__()
       7         self.n =  n
       8         self.sleep_time = sleep_time
       9     def run(self):
      10         print("runnint task ",self.n )
      11         time.sleep(self.sleep_time)
      12         print("task done,",self.n )
      13 
      14 
      15 t1 = MyThread("t1",2)
      16 t2 = MyThread("t2",4)
      17 
      18 t1.start()
      19 t2.start()
      20 
      21 t1.join() #=wait()
      22 t2.join()
      23 
      24 print("main thread....")
    • 线程锁Mutex
      • 互斥锁Lock:修改全局变量或者操作同一内存时只有一个线程操作,即同一时间只允许一个线程修改数据
         1 import threading
         2 import time
         3 
         4 def run(n):
         5     lock.acquire() #修改数据前加锁
         6     global  num
         7     num +=1
         8     time.sleep(1)
         9     lock.release() #修改后释放
        10 
        11 
        12 lock = threading.Lock() #生成全局锁(互斥锁)
        13 num = 0 #设定一个共享变量
        14 t_objs = [] #存线程实例
        15 for i in range(50):
        16     t = threading.Thread(target=run,args=("t-%s" %i ,))
        17     t.start()
        18     t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里
        19 
        20 for t in t_objs: #循环线程实例列表,等待所有线程执行完毕
        21     t.join()
        22 
        23 print("----------all threads has finished...",threading.current_thread(),threading.active_count())
        24 
        25 print("num:",num)
      • 递归锁RLock:在一个大锁中包含子锁
         1 import threading, time
         2 
         3 def run1():
         4     print("grab the first part data")
         5     lock.acquire()
         6     global num
         7     num += 1
         8     lock.release()
         9     return num
        10 
        11 def run2():
        12     print("grab the second part data")
        13     lock.acquire()
        14     global num2
        15     num2 += 1
        16     lock.release()
        17     return num2
        18 
        19 def run3():
        20     lock.acquire()
        21     res = run1()
        22     print('--------between run1 and run2-----')
        23     res2 = run2()
        24     lock.release()
        25     print(res, res2)
        26 
        27 num, num2 = 0, 0
        28 lock = threading.RLock() #递归锁
        29 for i in range(10):
        30     t = threading.Thread(target=run3)
        31     t.start()
        32 
        33 while threading.active_count() != 1:
        34     print(threading.active_count())
        35 else:
        36     print('----all threads done---')
        37     print(num, num2)
      • 信号量Semaphore:互斥锁同一时间只允许一个线程修改数据,而信号量是同时允许一定数量的线程更改数据。
         1 import threading, time
         2 
         3 def run(n):
         4     semaphore.acquire()
         5     time.sleep(1)
         6     print("run the thread: %s\n" % n)
         7     semaphore.release()
         8 
         9 if __name__ == '__main__':
        10     semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行
        11     for i in range(22):
        12         t = threading.Thread(target=run, args=(i,))
        13         t.start()
        14 while threading.active_count() != 1:
        15     pass
        16 else:
        17     print('----all threads done---')

         

  • 事件Events
    同进程的一样,线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象,而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行 。
    • event.isSet():返回event的状态值。获取内置标志状态,返回True或False
    • event.wait(timeout):如果 event.isSet()==False将阻塞线程。如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()
    • event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度。将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态
    • event.clear():恢复event的状态值为False。将标志设为False
       1 import time
       2 import threading
       3 
       4 event = threading.Event()
       5 
       6 def lighter():
       7     count = 0
       8     event.set() #先设置绿灯
       9     while True:
      10         if count >5 and count < 10: #改成红灯
      11             event.clear() #把标志位清了
      12             print("red light is on....")
      13         elif count >10:
      14             event.set() #变绿灯
      15             count = 0
      16         else:
      17             print("green light is on....")
      18         time.sleep(1)
      19         count +=1
      20         print(count)
      21 def car(name):
      22     while True:
      23         if event.is_set(): #代表绿灯
      24             print("[%s] running..."% name )
      25             time.sleep(1)
      26         else:
      27             print("[%s] sees red light , waiting...." %name)
      28             event.wait()
      29             print("[%s] green light is on, start going..." %name)
      30 
      31 
      32 light = threading.Thread(target=lighter,)
      33 light.start()
      34 
      35 car1 = threading.Thread(target=car,args=("Tesla",))
      36 car1.start()
  • 队列
    • 作用
      解耦:使程序直接实现松耦合,修改一个函数,不会有串联关系
      提高处理效率:FIFO(现进先出),LIFO(后入先出)
    • 队列
      队列可以并发的派多个线程,对排列的线程处理,并切每个需要处理线程只需要将请求的数据放入队列容器的内存中,线程不需要等待,当排列完毕处理完数据后,线程在准时来取数据即可。请求数据的线程只与这个队列容器存在关系,处理数据的线程down掉不会影响到请求数据的线程,队列会派给其他线程处理这分数据,它实现了解耦,提高效率。队列内会有一个有顺序的容器,列表与这个容器是有区别的,列表中数据虽然是排列的,但数据被取走后还会保留,而队列中这个容器的数据被取后将不会保留。当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用。
    • 四种类型的队例
      • Queue:先进先出队列
         1 from queue import Queue #LILO队列
         2 #基本FIFO队列  先进先出 FIFO即First in First Out,先进先出
         3 #maxsize设置队列中,数据上限,小于或等于0则不限制,容器中大于这个数则阻塞,直到队列中的数据被消掉
         4 q = Queue(maxsize=0)
         5 #写入队列数据
         6 q.put(0)
         7 q.put(1)
         8 q.put(2)
         9 #返回队列大小
        10 print(q.qsize())
        11 #如果队列为空,返回True
        12 print(q.empty())
        13 #如果队列满了,返回True,大小与maxsize的值对应
        14 print(q.full())
        15 #不等待,直接获取数据,如队列为空,则不等待队列放入信息后取出数据,直接报错
        16 print(q.get_nowait())
        17 #不等待,直接写入数据,如队列已满,则不等待队列信息取出后再放入,直接报错
        18 q.put_nowait(3)
        19 #输出当前队列所有数据
        20 print(q.queue)
        21 #删除队列数据,并返回该数据
        22 q.get()
        23 #输也所有队列数据
        24 print(q.queue)
      • LifoOueue:后进先出队列
         1 from queue import LifoQueue #LIFO队列
         2 #LIFO即Last in First Out,后进先出。与栈的类似,使用也很简单,maxsize用法同上
         3 lq = LifoQueue(maxsize=0)
         4 #队列写入数据
         5 lq.put(0)
         6 lq.put(1)
         7 lq.put(2)
         8 #输出队列所有数据
         9 print(lq.queue)
        10 #删除队尾数据,并返回该数据
        11 lq.get()
        12 #输出队列所有数据
        13 print(lq.queue)
      • PriorityQueue:优先队列
         1 from queue import PriorityQueue #优先队列
         2 # 存储数据时可设置优先级的队列,优先级设置数越小等级越高
         3 pq = PriorityQueue(maxsize=0)
         4 #写入队列,设置优先级
         5 pq.put((9,'a'))
         6 pq.put((7,'c'))
         7 pq.put((1,'d'))
         8 #输出队例全部数据
         9 print(pq.queue)
        10 #取队例数据,可以看到,是按优先级取的。
        11 pq.get()
        12 pq.get()
        13 print(pq.queue)
      • deque:双端队列
         1 from collections import deque   #双端队列
         2 #双边队列
         3 dq = deque(['a','b'])
         4 #增加数据到队尾
         5 dq.append('c')
         6 #增加一组数据到队尾
         7 dq.extend(['d','e'])
         8 #增加数据到队头
         9 dq.appendleft('f')
        10 #增加一组数据到队头
        11 dq.extendleft(['g','h'])
        12 #指定位置插入
        13 dq.insert(2,'i')
        14 #输出队列所有数据
        15 print(dq)
        16 #移除队尾并返回
        17 print(dq.pop())
        18 #移除队头并返回
        19 print(dq.popleft())
        20 #循环右移2次并返回
        21 print(dq.rotate(2))
        22 #循环左移3次并返回
        23 print(dq.rotate(-3))

         

posted @ 2019-06-16 22:41  飞琼君  阅读(140)  评论(0编辑  收藏  举报