精华内容
下载资源
问答
  • 经常说的一个话题:Python多线程是假的多线程。具体python为什么在多线程方面比较弱呢?以下资料来自于网络的整理。全局解释器锁(GIL)Python代码的执行由Python虚拟机(解释器)来控制。Python在设计之初就考虑要...

    学习还是要多总结,不然老忘啊。

    经常说的一个话题:Python多线程是假的多线程。具体python为什么在多线程方面比较弱呢?

    以下资料来自于网络的整理。

    全局解释器锁(GIL)

    Python代码的执行由Python虚拟机(解释器)来控制。

    Python在设计之初就考虑要在主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时刻,只有一个程序在CPU中运行。

    同样地,虽然Python解释器可以运行多个线程,只有一个线程在解释器中运行。

    对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个线程在运行。在多线程环境中,Python虚拟机按照以下方式执行。

    设置GIL。

    切换到一个线程去执行。

    运行。

    把线程设置为睡眠状态。

    解锁GIL。

    再次重复以上步骤。

    对所有面向I/O的(会调用内建的操作系统C代码的)程序来说,GIL会在这个I/O调用之前被释放,以允许其他线程在这个线程等待I/O的时候运行。如果某线程并未使用很多I/O操作,它会在自己的时间片内一直占用处理器和GIL。也就是说,I/O密集型的Python程序比计算密集型的Python程序更能充分利用多线程的好处。

    我们都知道,比方我有一个4核的CPU,那么这样一来,在单位时间内每个核只能跑一个线程,然后时间片轮转切换。但是Python不一样,它不管你有几个核,单位时间多个核只能跑一个线程,然后时间片轮转。看起来很不可思议?但是这就是GIL搞的鬼。任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。通常我们用的解释器是官方实现的CPython,要真正利用多核,除非重写一个不带GIL的解释器。

    即:

    你就不应该用Python写CPU密集型的代码…效率摆在那里…

    如果确实需要在CPU密集型的代码里用concurrent,就去用multiprocessing库。这个库是基于multi process实现了类multi thread的API接口,并且用pickle部分地实现了变量共享。

    再加一条,如果你不知道你的代码到底算CPU密集型还是IO密集型,教你个方法:multiprocessing这个module有一个dummy的sub module,它是基于multithread实现了multiprocessing的API。假设你使用的是multiprocessing的Pool,是使用多进程实现了concurrency

    from multiprocessing import Pool

    如果把这个代码改成下面这样,就变成多线程实现concurrency

    from multiprocessing.dummy import Pool

    两种方式都跑一下,哪个速度快用哪个就行了。

    此外,还有concurrent.futures这个东西,包含ThreadPoolExecutor和ProcessPoolExecutor,可能比multiprocessing更简单

    concurrent.futures

    concurrent.futures实例:

    python concurrent.futures https://www.cnblogs.com/kangoroo/p/7628092.html

    用c语言链接库来解决cpu密集型任务的多核多线程问题

    难道就如此?我们没有办法在Python中利用多核?当然可以!刚才的多进程算是一种解决方案,还有一种就是调用C语言的链接库。对所有面向I/O的(会调用内建的操作系统C代码的)程序来说,GIL会在这个I/O调用之前被释放,以允许其他线程在这个线程等待I/O的时候运行。我们可以把一些 计算密集型任务用C语言编写,然后把.so链接库内容加载到Python中,因为执行C代码,GIL锁会释放,这样一来,就可以做到每个核都跑一个线程的目的!

    总结

    Python多线程相当于单核多线程,多线程有两个好处:CPU并行,IO并行,单核多线程相当于自断一臂。所以,在Python中,可以使用多线程,但不要指望能有效利用多核。如果一定要通过多线程利用多核,那只能通过C扩展来实现,不过这样就失去了Python简单易用的特点。不过,也不用过于担心,Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。

    参考

    展开全文
  • 目前Python 提供了几种多线程实现方式 thread,threading,multithreading ,其中thread模块比较底层,而threading模块是对thread做了一些包装,可以更加方便的被使用。2.7版本之前python对线程的支持还不够完善,不...

    目前Python 提供了几种多线程实现方式 thread,threading,multithreading ,其中thread模块比较底层,而threading模块是对thread做了一些包装,可以更加方便的被使用。

    2.7版本之前python对线程的支持还不够完善,不能利用多核CPU,但是2.7版本的python中已经考虑改进这点,出现了multithreading 模块。threading模块里面主要是对一些线程的操作对象化,创建Thread的class。一般来说,使用线程有两种模式:

    A 创建线程要执行的函数,把这个函数传递进Thread对象里,让它来执行;

    B 继承Thread类,创建一个新的class,将要执行的代码 写到run函数里面。

    本文介绍两种实现方法。

    第一种 创建函数并且传入Thread 对象中

    t.py 脚本内容

    import threading,time

    from time import sleep, ctime

    def now() :

    return str( time.strftime( '%Y-%m-%d %H:%M:%S' , time.localtime() ) )

    def test(nloop, nsec):

    print 'start loop', nloop, 'at:', now()

    sleep(nsec)

    print 'loop', nloop, 'done at:', now()

    def main():

    print 'starting at:',now()

    threadpool=[]

    for i in xrange(10):

    th = threading.Thread(target= test,args= (i,2))

    threadpool.append(th)

    for th in threadpool:

    th.start()

    for th in threadpool :

    threading.Thread.join( th )

    print 'all Done at:', now()

    if __name__ == '__main__':

    main()

    执行结果:

    140609165458561.jpg

    thclass.py 脚本内容:

    import threading ,time

    from time import sleep, ctime

    def now() :

    return str( time.strftime( '%Y-%m-%d %H:%M:%S' , time.localtime() ) )

    class myThread (threading.Thread) :

    """docstring for myThread"""

    def __init__(self, nloop, nsec) :

    super(myThread, self).__init__()

    self.nloop = nloop

    self.nsec = nsec

    def run(self):

    print 'start loop', self.nloop, 'at:', ctime()

    sleep(self.nsec)

    print 'loop', self.nloop, 'done at:', ctime()

    def main():

    thpool=[]

    print 'starting at:',now()

    for i in xrange(10):

    thpool.append(myThread(i,2))

    for th in thpool:

    th.start()

    for th in thpool:

    th.join()

    print 'all Done at:', now()

    if __name__ == '__main__':

    main()

    执行结果:

    140609165458562.jpg

    Python 的详细介绍:请点这里

    Python 的下载地址:请点这里

    logo.gif

    展开全文
  • 并发:假同时,一段时间内同时处理个任务并行:真同时,同时处理个任务,必须多核,是并发的子集threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)线程import ...

    并发:假同时,一段时间内同时处理多个任务

    并行:真同时,同时处理多个任务,必须多核,是并发的子集

    threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

    线程

    import threading

    def worker():

    print('work')

    thread = threading.Thread(target=worker) # 创建线程对象,target参数是一个函数,这个函数即线程要执行的逻辑

    thread.start() # start函数启动一个线程,当这个线程的逻辑执行,设计自动退出,自己退出。

    import time

    def worker(num):

    time.sleep(1)

    print('worker-{}'.format(num))

    for z in range(5):

    t = threading.Thread(target=worker, args=(z, )) # 元组参数列表

    t.start()

    如何标识一个线程

    threading.current_thread() # 返回当前线程

    <<<_MainThread(MainThread, started 140428986173248)>

    thread = threading.current_thread()

    thread.name # 线程名,可重名

    <<'MainThread'

    thread.ident # 线程id

    <<140428986173248

    logging

    import logging

    logging.warning('haha')

    <

    import importlib

    importlib.reload(logging) # 重新引入,覆盖缓存

    # import导入一次会在缓存中固定,,reload会从标准库中导入

    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(threadName)s %(message)s') # 配置logging

    logging.warning('haha') # 替代print

    <<2017-03-11 09:42:47,814 WARNING [MainThread haha]

    参数

    # 通过args参数传递位置参数,通过kwargs传递关键字参数

    def add(x, y):

    logging.info(x + y)

    add(1, 2)

    add(x=1, y=2)

    threading.Thread(target=add, args=(1, 2)).start()

    threading.Thread(target=add, kwargs={'x':1, 'y':2}).start()

    threading.Thread(target=add, args=(1,), kwargs={'y':2}).start()

    <<2017-03-11 09:45:23,651 INFO [Thread-18 3]

    线程名

    threading.Thread(target=add, args=(1, 2), name='adc').start()

    2017-03-11 09:47:55,442 INFO [adc 3]

    # 通过name参数设置线程名字,日志可以带线程名

    # 线程可以重名,唯一标识符是id,但是通常应该避免线程重名。通常线程名命名加前缀

    线程通信的必要

    importlib.reload(logging)

    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s %(message)s]')

    def ww(num):

    logging.info('ww-{}--'.format(num))

    time.sleep(1)

    logging.info('ww-{}'.format(num))

    for i in range(5):

    t = threading.Thread(target=ww, args=(i, ), name='ww1')

    t.start()

    for i in range(5):

    t = threading.Thread(target=ww, args=(i, ), name='ww2')

    t.start()

    <<2017-03-11 10:24:58,067 INFO [ww1 ww-0--]

    <<2017-03-11 10:24:58,071 INFO [ww1 ww-1--]

    <<2017-03-11 10:24:58,074 INFO [ww1 ww-2--]

    <<2017-03-11 10:24:58,076 INFO [ww1 ww-3--]

    <<2017-03-11 10:24:58,078 INFO [ww1 ww-4--]

    <<2017-03-11 10:24:58,081 INFO [ww2 ww-0--]

    <<2017-03-11 10:24:58,084 INFO [ww2 ww-1--]

    <<2017-03-11 10:24:58,086 INFO [ww2 ww-2--]

    <<2017-03-11 10:24:58,105 INFO [ww2 ww-3--]

    <<2017-03-11 10:24:58,121 INFO [ww2 ww-4--]

    <<2017-03-11 10:24:59,073 INFO [ww1 ww-0]

    <<2017-03-11 10:24:59,074 INFO [ww1 ww-1]

    <<2017-03-11 10:24:59,077 INFO [ww1 ww-2]

    <<2017-03-11 10:24:59,080 INFO [ww1 ww-3]

    <<2017-03-11 10:24:59,082 INFO [ww1 ww-4]

    <<2017-03-11 10:24:59,086 INFO [ww2 ww-0]

    <<2017-03-11 10:24:59,087 INFO [ww2 ww-1]

    <<2017-03-11 10:24:59,106 INFO [ww2 ww-2]

    <<2017-03-11 10:24:59,122 INFO [ww2 ww-3]

    <<2017-03-11 10:24:59,130 INFO [ww2 ww-4]

    # 多线程自动并发,各线程调度顺序需要进程间通信来控制

    daemon

    # 在pycharm中

    import time

    import logging

    import threading

    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s %(message)s]')

    def worker1():

    logging.info('starting')

    time.sleep(20)

    logging.info('completed')

    def worker2():

    logging.info('starting')

    time.sleep(3)

    logging.info('completed')

    if __name__ == '__main__':

    logging.info('start1')

    t = threading.Thread(target=worker1, name='non-daemon')

    t.start()

    t = threading.Thread(target=worker2, daemon=True, name='daemon')

    t.start()

    logging.info('stop1')

    <<2017-03-11 11:30:08,007 INFO [MainThread start1]

    <<2017-03-11 11:30:08,026 INFO [non-daemon starting]

    <<2017-03-11 11:30:08,044 INFO [daemon starting]

    <<2017-03-11 11:30:08,045 INFO [MainThread stop1]

    <<2017-03-11 11:30:11,048 INFO [daemon completed]

    <<2017-03-11 11:30:28,040 INFO [non-daemon completed]

    # daemon参数默认False

    # daemon标记的子线程会随父线程退出而退出,可能执行完,可能未执行完

    # none-daemon标记的子线程,主线程会等待其执行完再退出

    依靠时间片解述:

    125157_FSdb_2698055.png

    125208_e5Tv_2698055.png

    join

    # join方法会阻塞,直到线程退出或者超时,timeout 是可选的,如果不设置timeout,会一直等待线程退出。不占用CPU时间

    # 可用来强制等待deamon线程执行完成

    t.join()

    # 默认等待退出

    t.join(timeout)

    # 等待超时

    thread local

    del(thread) # 删除对象

    ctz = threading.local()

    ctz.data = 5

    data = 'abc'

    def worker():

    logging.info(data)

    logging.info(ctz.data)

    worker()

    <<2017-03-11 11:19:16,158 INFO [MainThread abc]

    <<2017-03-11 11:19:16,173 INFO [MainThread 5]

    threading.Thread(target=worker).start()

    <<2017-03-11 11:21:12,623 INFO [Thread-23 abc]

    # threading.local()增加的属性只存在当前线程,只对当前线程可见

    定时器/延迟执行

    def worker():

    logging.info('run')

    t = threading.Timer(interval=5, function=worker) # 用function不是target

    t.start() # 停顿5秒 执行,没有name

    t.name

    <<'Thread-28'

    <<2017-03-11 11:37:50,080 INFO [Thread-28 run]

    t.name = 'worker' # 这样设置name

    t.start()

    t.cancel()

    # 取消执行,线程结束。 在start后,在interval内,之间存在

    threading.enumerate() # 查看当前所有线程

    def worker():

    logging.info('starting')

    time.sleep(30)

    logging.info('completed')

    t = threading.Timer(interval=0, function=worker)

    t.start()

    <<2017-03-11 11:45:50,224 INFO [Thread-32 starting]

    t.cancel()

    t.is_alive()

    <

    <<2017-03-11 11:46:20,248 INFO [Thread-32 completed]

    # 当function参数指定函数开始执行的时候,cancel无效,无法取消

    展开全文
  • What is the difference between multiprocessor programming and multicore ...preferably show examples in python how to write a small program for multiprogramming & multicore programming解决方案...

    What is the difference between multiprocessor programming and multicore programming?

    preferably show examples in python how to write a small program for multiprogramming & multicore programming

    解决方案

    There is no such thing as "multiprocessor" or "multicore" programming. The distinction between "multiprocessor" and "multicore" computers is probably not relevant to you as an application programmer; it has to do with subtleties of how the cores share access to memory.

    In order to take advantage of a multicore (or multiprocessor) computer, you need a program written in such a way that it can be run in parallel, and a runtime that will allow the program to actually be executed in parallel on multiple cores (and operating system, although any operating system you can run on your PC will do this). This is really parallel programming, although there are different approaches to parallel programming. The ones that are relevant to Python are multiprocessing and multithreading.

    In languages like C, C++, Java, and C#, you can write parallel programs by executing multiple threads. The global interpreter lock in the CPython and PyPy runtimes preclude this option; but only for those runtimes. (In my personal opinion, multithreading is dangerous and tricky and it is generally a good thing that Python encourages you not to consider it as a way to get a performance advantage.)

    If you want to write a parallel program which can run on multiple cores in Python, you have a few different options:

    Write a multithreaded program using the threading module and run it in the IronPython or Jython runtime.

    Use the processing module, (now included in Python 2.6 as the multiprocessing module), to run your code in multiple processes at once.

    Use the subprocess module to run multiple python interpreters and communicate between them.

    Use Twisted and Ampoule. This has the advantage of not just running your code across different processes, but (if you don't share access to things like files) potentially across different computers as well.

    No matter which of these options you choose, you will need to understand how to split the work that your program is doing up into chunks that make sense to separate. Since I'm not sure what kind of programs you are thinking of writing, it would be difficult to provide a useful example.

    展开全文
  • 本文首发于本人博客,转载请注明出处写在前面作者电脑有 4 个 CPU,因此使用 4 个线程测试是合理的本文使用的 cpython 版本为 3.6.4本文使用的 pypy 版本为 5.9.0-beta0,兼容 Python 3.5 语法本文使用的 jython ...
  • What is the difference between multiprocessor programming and multicore ...preferably show examples in python how to write a small program for multiprogramming & multicore programming解决方案Ther...
  • python中的并行由于cpython中的gil的存在我们可以暂时不奢望能在cpython中使用多线程利用多核资源进行并行计算了,因此我们在python中可以利用多进程的方式充分利用多核资源。 python中我们可以使用很多方式进行多...
  • 昨天晚上在寝室写python多线程的时候,用了几个测试的程序,分别是递归方法求斐波那契数的值。分别采用单线程一个一个执行的方法和采用多线程调用的方法。观察所用的时间基本上差不多的。然后我在每个函数内部加入...
  • 本次给大家介绍Python多线程编程,标题如下:Python多线程简介Python多线程之threading模块Python多线程之Lock线程锁Python多线程之Python的GIL锁Python多线程之ThreadLocal多进程与多线程比较多进程与多线程比较...
  • 使用多线程编程,以及类似 Queue 的共享数据结构,这个编程任务可以规划成几个执行特定函数的线程: •UserRequestThread:负责读取客户端输入,该输入可能来自 I/O 通道。程序将创建多个线程,...
  • 转自:http://www.cnblogs.com/skying555/p/6527189.htmlGIL 与 Python 线程的纠葛GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题。运行下面这段 python 程序,CPU 占用率是多少?#...
  • GIL 与 Python 线程的纠葛GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题。运行下面这段 python 程序,CPU 占用率是多少?# 请勿在工作中模仿,危险:)def dead_loop():while True:...
  • Python多线程编程学习笔记 文章目录Python多线程编程学习笔记写在前面1. 多进程2. 多线程3. 补充 写在前面 学习链接: 2小时玩转python多线程编程 Threading 学会多线程 (莫烦 Python 教程) 1. 多进程 多任务...
  • 本文实例讲述了Python多线程编程之多线程加锁操作。分享给大家供大家参考,具体如下:Python语言本身是支持多线程的,不像PHP语言。下面的例子是多个线程做同一批任务,任务总是有task_num个,每次线程做一个任务...
  • 文章目录一、多线程模块基础使用启动线程其他方法二、全局解释器锁GIL三、多线程实现socket 一、多线程模块基础使用 启动线程 使用方法一: from threading import Thread def func1(i): print("我是线程%d"%i) ...
  • Python多线程编程

    2018-07-04 09:22:15
    Python多线程编程文档说明 多进程编程 一、 multiprocessing 模块 1. multiprocessing 模块提供了多进程编程的能力 它的API非常类似于 threading 模块,但是也提供了一些threading 模块不具有的能力 相比于线程,它...
  • 一、先来讲讲进程、线程、协程的区别和应用场景进程:多进程适用于CUP密集型,可以多核操作,使用多进程稳定性好,当一个子进程崩溃了,不会影响主进程和其他子进程线程:多线程适用于I/O密集型,如果是I/O操作,多...
  • python多线程编程

    2020-05-10 11:21:42
    python多线程编程实现方式 先写个总括,后面再慢慢补充,细化,修正 背景 IO速度远低于计算速度,以及CPU成本降低,如何高效利用多核CPU是多进程和多线程产生的背景 线程VS进程 使用一个简单的例子说明,使用word...
  • 本文试图搞明白Python多线程编程
  • GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题。运行下面这段 python 程序,CPU 占用率是多少? # 请勿在工作中模仿,危险:) def dead_loop(): ...
  • python多线程编程(下) 文章目录python多线程编程(下)前言一、线程的介绍1.1 实现多任务的另一种形式1.2 为什么使用多线程1.3 多线程的作用1.4 多线程的作用1.5 总结二、多线程完成多任务2.1 线程的创建步骤2.2 ...
  • Python多线程编程初步探索(二)多个线程 多个线程 关于同步、锁的问题 真正的多线程在操作系统底层是如何实现的呢?——GIL(全局解释器锁)。无论你启多少个线程,你有多少个cpu, Python在执行一个进程的时候会...
  • 谈谈python多线程编程

    2018-12-14 13:29:00
    谈谈python多线程编程 Python中GIL概念 GIL机制分析 threading、multiprocessing两都的不同点 实例分析
  • 1. 多线程编程与线程安全相关重要概念 开始之前,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作。 GIL: Global Interpreter Lock,全局解释器锁。 Cpython解释器上的一把互斥锁,不能利用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,033
精华内容 5,213
关键字:

python多核多线程编程

python 订阅