我使用了多线程执行独立代码(它们之间没有任何公共代码),但这一次,我必须使用一个在每个线程中调用的公共函数。所以,如果能起作用我会有点困惑。例如,
thread1:
#do something
input_list = [5,6,7,8]
output_list = common_function(input_list)
print output_list
thread2:
#do something
input_list = [1,2,3,4]
output_list = common_function(input_list)
print output_list
上述代码是否会成为一个问题,也许是因为竞争条件?或者python会自动处理这个? common_function(input_data)根据提供的输入返回一个列表,然后显示该列表。对于一个小数据集,它可以工作,但我的问题是,如果input_list变得庞大,是否会导致代码出现问题?
答案 0 :(得分:1)
如果common_function
是一个没有任何副作用的函数,那就是保存。换句话说,如果common_function
仅适用于input_list
并且不使用任何其他内容(没有共享数据,没有服务),则可以并行调用该函数。只要不与任何其他线程共享,输入数据的大小就无关紧要。
答案 1 :(得分:0)
如果您使用的是threading
软件包,则可以在写入之前使用semaphore
锁定变量。就像这里的例子:
import threading
lock = threading.BoundedSemaphore()
def function():
lock.acquire() # Lock the Variable
# Write to your List
lock.release() # Release the Variable
因此,acquire
和release
之间的所有内容都是为线程保存
答案 2 :(得分:0)
正如@lutz所写,如果common_function
的两个实例之间没有共享数据,则不存在竞争条件的危险。这就是引用透明度的含义,通常所有编程语言都认为这些函数应该是线程安全的。有时,您需要编写和使用改变某些全局状态的函数。在这种情况下,现代格言是使用事件驱动编程 - 这意味着不在线程之间直接通信,而是通过一些线程安全排队系统进行通信。在python中,我是queue module的忠实粉丝。另一个好的队列模块是multiprocessing.queue,其中一个很好的例子是here。我也在这里粘贴代码。
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # prints "[42, None, 'hello']"
p.join()
最后,如果你对某些功能没有信心(可能它是一个很大的功能而且你不了解它的螺母和螺栓),我建议你使用模糊方法。在这里定义一个简单的函数
FUZZ = True
def fuzz():
"""
fuzzing is a technique to make the race condition errors more visible
"""
if FUZZ:
time.sleep(random.random())
然后将此函数放在代码中的随机位置。这应该放大代码中存在的任何竞争条件。这当然不是一种保证方法,所以如果你的函数在生产应用程序中被调用了数百万次,那么更好的策略就是将函数分解为更小的易消化部分。观看Raymond Hettinger在his famous talk on python threading发表关于并发代码的演讲。您可以获得他正在谈论的代码here。