zoukankan      html  css  js  c++  java
  • 7.多线程编程

    在python中又有多种多线程的方式,但是其中某些由于过于古老以及某些操作不易实现,所以大多已经淘汰(例如thread模块),现在多使用threading模块,其中的Thread类基本完全取代thread模块,而且更方便。

    在此,我记录一下我看这个模块时候迷惑的一点

    创建多线程有三个方式:

    1.创建Thread的实例,传给它一个函数。

    2.创建Thread的实例,传给它一个可调用的类实例。

    3.创建Thread的子类,并创建子类的实例。

    注意:这一点可理解为既然你创建了一个线程,那么必然是用来执行某些东西的,所以你必须制定一个需要执行的代码,比如一个函数,一个可调用的类,当然你也可以创建一些值,那瞬间就完成了,使用额外的线程是为了什么呢?也就是说你肯定需要一个耗费时间的操作才会用多线程。这样就可以理解上述三个方式了。

    以第三种方式,贴一段代码来进行具体标记:

     1 import threading
     2 from time import sleep, ctime
     3 
     4 loops = [4, 2]
     5 
     6 class MyThread(threading.Thread):
     7     def __init__(self, func, args, name=''):
     8         threading.Thread.__init__(self, name=name)
     9         self.func = func
    10         self.args = args
    11 
    12     def run(self):
    13         self.func(*self.args)
    14 
    15 def loop(nloop, nsec):
    16     print 'start loop', nloop, 'at:', ctime()
    17     sleep(nsec)
    18     print 'loop', nloop, 'done at:', ctime()
    19 
    20 def main():
    21     print 'starting at:', ctime()
    22     threads = []
    23     nloops = range(len(loops))
    24 
    25     for i in nloops:
    26         t = MyThread(loop, (i, loops[i]),
    27             loop.__name__)
    28         threads.append(t)
    29 
    30     for i in nloops:
    31         threads[i].start()
    32 
    33     for i in nloops:
    34         threads[i].join()
    35 
    36     print 'all DONE at:', ctime()
    37 
    38 if __name__ == '__main__':
    39     main()

    这里需要特别注意的是第8行:主动调用了基类的初始化函数,不太理解为什么,重写了,应该就直接用自己的就行了。希望大神指教。

    还有就是26行,这个子类的实例化,传入的参数,第一个是一个函数,第二个是这个函数的参数,第三个是这个函数的名字。

    不过第12行不清楚为什么,也不清楚run这个函数的用途,之后理解了在补充吧。

    按照上边的步骤就是多线程的简单运用。

    本来我不是很理解join()函数的作用,但是通过输出我发现了一点猫腻。

    1 $ mtsleepD.py
    2 starting at: Sun Aug 13 18:49:17 2006
    3 start loop 0 at: Sun Aug 13 18:49:17 2006
    4 start loop 1 at: Sun Aug 13 18:49:17 2006
    5 loop 1 done at: Sun Aug 13 18:49:19 2006
    6 loop 0 done at: Sun Aug 13 18:49:21 2006
    7 all DONE at: Sun Aug 13 18:49:21 2006

    根据上边输出可以看出来,按照代码中的执行顺序,loop 0先开始,然后loop 1再开始。

    但是第5行可以看出来,是loop 1先执行完毕的。

    所以 join的作用是:

    A 线程正在运行,当B线程进行Join操作后,A线程会被阻断,进入等待队列。

    B线程执行,当B线程执行完毕后,B线程的资源收回,A线程进去执行队列。

    A线程继续进行执行

    然而对于多线程来说,遇到的最大的问题就是在遇到IO密集的应用时,怎么在使用多线程的同时避免数据的不同步,此时就需要使用通常意义上的所说的锁了,当然还有信息量。

     1 from atexit import register
     2 from random import randrange
     3 from threading import Thread, Lock, currentThread
     4 from time import sleep, ctime
     5 
     6 class CleanOutputSet(set):
     7     def __str__(self):
     8         return ', '.join(x for x in self)
     9 
    10 lock = Lock()
    11 loops = (randrange(2, 5) for x in range(randrange(3, 7)))
    12 remaining = CleanOutputSet()
    13 
    14 def loop(nsec):
    15     myname = currentThread().name
    16     lock.acquire()
    17     remaining.add(myname)
    18     print('[%s] Started %s' % (ctime(), myname)) #print '[{0}] Started {1}'.format(ctime(), myname)
    19     lock.release()
    20     sleep(nsec)
    21     lock.acquire()
    22     remaining.remove(myname)
    23     print('[%s] Completed %s (%d secs)' % ( #print '[{0}] Completed {1} ({2} secs)'.format(
    24         ctime(), myname, nsec))
    25     print('    (remaining: %s)' % (remaining or 'NONE')) #print '    (remaining: {0})'.format(remaining or 'NONE')
    26     lock.release()
    27 
    28 def _main():
    29     for pause in loops:
    30         Thread(target=loop, args=(pause,)).start()
    31 
    32 @register
    33 def _atexit():
    34     print('all DONE at:', ctime())
    35 
    36 if __name__ == '__main__':
    37     _main()

    以上就是一个使用锁的例子,使用acquire来获取锁,使用release释放,

    如若使用with会更加简洁,如下。

    1 with lock:
    2   remaining.add(myname)
    3   print '[%s] Started %s' % (ctime(), myname)
    4 sleep(nsec)

    关于信息量的就不多说了,其实就是请求一个事先设定好大小的资源池,每次需要新的线程就从池子调用,池子空了就无法再调用新的。

    接下来是一些多线程的其他模块,需要的话可以详细查询。

  • 相关阅读:
    日志框架1---多种日志门面和日志实现初步了解(转载)
    @Autowired 与@Resource的区别(转)
    Spring 之jdbc模板(JdbcTemplate与NamedParameterJdbcTemplate)
    springMVC中的Controller里面定义全局变量
    spring批量更新数据 ---- BatchPreparedStatementSetter
    easyui树查找
    根据ID和parentID利用Java递归获取全路径名称
    一个统一将数据转换为JSON的方法
    上传图片并限制图片格式和大小
    js上传文件(图片)的格式和大小限制
  • 原文地址:https://www.cnblogs.com/lixiaofou/p/7707970.html
Copyright © 2011-2022 走看看