الحوسبة البطيئة في الحياة اليومية

وعلى الرغم من أن الأشخاص الذين يستخدمون نصوص بايثون لكتابة قائمة تسوق أو تجميع بيانات الإيجار يتم تجميعها عن طريق الرأس ، ولكن إذا حدث ذلك ، فإنك تستخدم النصوص البرمجية لحل المهام الروتينية وأحيانًا تعمل النصوص البرمجية لفترة طويلة بشكل غير مقبول ، فإن الفكرة هي استخدام الحسابات الكسولة إلى كل شيء يتحرك ، ستحبه.


في الفصول السابقة من رسالتي ، أعطيت وصفًا مجانيًا لتشغيل مكتبة Evalcache.
الارتباط: التخزين المؤقت على القرص لأشجار الحوسبة الكسولة


لكي لا تمل منك الحاجة لدراسة هذه المواد قبل قراءة هذا ، ملخص موجز للجزء الأخير:


يقوم لفائف التخزين المؤقت بتغليف البيانات والوظائف والأساليب في الأشياء الكسولة. يحتوي كل كائن كسول على مفتاح تجزئة خاص يتميز بطريقة بنائه. يمكن إجراء العمليات على الأجسام الكسولة ، مما يؤدي إلى توليد أجسام كسولة جديدة. تبدو هذه العمليات تمامًا مثل العمليات على البيانات العادية ، ولكن في الواقع لا يتم إجراء العمليات الحسابية ؛ بدلاً من ذلك ، يتم إنشاء شجرة من الكائنات البطيئة التي تشير إلى بعضها البعض ، وتتذكر عملياتها وحججها. إذا كان من الضروري الحصول على البيانات ، يتم إجراء عملية لفتح الكائن الكسول ، الذي ينشط سلسلة الحسابات ، أو يسحب النتيجة من ذاكرة التخزين المؤقت ، إذا تم حساب الكائن مع هذا المفتاح في وقت سابق.


حول بعض التغييرات


منذ كتابة المقال الأخير ، حصل على تقييم ميكانيكي إضافي.


ميكانيكا تنفيذ غير مخبأة


اتضح أن تجزئة كائن كسول هو شيء مفيد للغاية تريد استخدامه في موقف يكون فيه تخزين الكائن نفسه مستحيلًا وغير ضروري.


تم إدخال بناء جملة خاص لهذا الغرض:


lazyhash = evalcache.LazyHash() #: #evalcache.Lazy(self, cache=None, fastdo=True) @lazyhash def foo(): ... 

في هذا الإصدار ، يتم حساب الكائن على الفور في وقت الإنشاء ، ولكن يتم إرجاع ملف كسول على أي حال. هذا يسمح لك ببناء أشجار حسابية دون الحاجة إلى تخزين بعض الأشياء في ذاكرة التخزين المؤقت.


ميكانيكا الإفشاء الضمني


الكشف الضمني هو السلوك المتوقع للمذكر. على الرغم من أن Evalcache تم تصميمه في الأساس ليس من أجل التذكر ، ولكن للعمل مع أشجار الحساب ، يمكن تحقيق الكشف الضمني القائم على خوارزميات Evalcache. onuse تم تقديم خيارين onplace onuse . يؤدي onplace إلى الكشف عن الكائن البطيء بعد الإنشاء مباشرةً ، ويؤدي الاستخدام عند محاولة استخدامه في بعض العمليات المسموح بها للجسم البطيء.


 import evalcache lazy = evalcache.Lazy(cache={}, onuse=True) #lazy = evalcache.Lazy(cache={}, onplace=True) ###   . #lazy = evalcache.Memoize() ###   . #lazy = evalcache.Memoize(onplace=True) ###   . @lazy def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2) for i in range(0,100): print(fib(i)) 

لكننا لا نتحدث عن هذه الإضافة غير الضرورية ، المصممة لجعل المكتبة أكثر تشابهًا مع المتدربين الآخرين. وحول الملفات البطيئة:


ملفات كسولة


يحتوي Evalcache على وظيفة إضافية لتدعيم الوظائف التي تنشئ الملفات. في البداية ، كان من المفترض استخدام هذه الوظيفة لتيسير إنشاء لقطات الشاشة. كما اتضح لاحقًا ، باستخدام آليات الملفات البطيئة ، يمكنك القيام بأشياء أخرى مثيرة للاهتمام.


 import evalcache import evalcache.lazyfile lazyfile = evalcache.lazyfile.LazyFile(cache = evalcache.DirCache(".evalfile")) @lazyfile(field="path") def foo(data, path): f = open(path, "w") f.write(data) f.close() foo("HelloWorld","data.dat") 

كيف يعمل ...
بشكل عام ، منطق العمل هو نفسه كما هو الحال مع جميع الأشياء البطيئة.
foo("HelloWorld","data.dat") يبدأ في إنشاء كائن كسول يرتبط مفتاح التجزئة به بالحجج التي تم تمريرها إليه. بعد ذلك ، يتم تطبيق آليات الكشف الضمني ، مما يؤدي إلى البدء الفوري للحساب.


ولكن بعد ذلك يتغير مسار العمل.
@lazyfile(field="path") يزين مصمم lazyfile معلمة بالاسم المحدد في الحقل. يتوقع مصمم الديكور أنه عند تنفيذ الوظيفة ، سيتم إنشاء ملف على هذا المسار. نقي ملفّ ذاكرة التخزين هذا الملف وينشئ ارتباطًا ".evalfile" دليل التجزئة ".evalfile" . يتوافق اسم ملف الرابط الثابت مع مفتاح التجزئة للكائن الكسول. لاحقًا ، عندما يكون هناك ملف بهذا الاسم في ذاكرة التخزين المؤقت ، تقوم Evalcache ، عند توسيع الكائن بدلاً من استدعاء الوظيفة ، بإنشاء ارتباط ثابت في المكان المطلوب للملف الموجود في ذاكرة التخزين المؤقت.


من المفيد أن يكون الملف الكسول كائنًا كسولًا عاديًا ، ويمكن استخدام كائنات كسولة أخرى لتوليده.


 import evalcache import evalcache.lazyfile lazy = evalcache.lazy.Lazy(cache = evalcache.DirCache(".evalcache")) lazyfile = evalcache.lazyfile.LazyFile(cache = evalcache.DirCache(".evalfile")) @lazyfile(field="path") def foo(data, path): f = open(path, "w") f.write(data) f.close() @lazy def datagenerator(): return "HelloWorld" foo(datagenerator(),"data.dat") 

تطبيق lenification لتحرير الفيديو من خلال أداة moviepy.


كما تعلمون ، يمكن حل أي مهمة باستخدام نص بيثون. مجموعة مكتبات Python واسعة للغاية لدرجة أن العثور على مهمة لا تغطيها وحدات Python أمر صعب للغاية.


على وجه الخصوص ، مكتبة الأفلام وساعتين من دراسة الوثائق الخاصة بها تعطينا محرر فيديو بسيط وعملي. التثبيت - من فضلك. صوت لفرض - من فضلك. المؤثرات الخاصة - من فضلك.


ومع ذلك ، كما هو الحال دائمًا ، فإن العمل مع البرامج النصية له عيب. في كل مرة يتم تشغيل البرنامج النصي ، يتم إعادة بناء جميع القطع الأثرية مرة أخرى. عند تثبيت فيديو مدته ساعة واحدة ، يمكن أن يستمر تشغيل مثل هذا البرنامج النصي لفترة طويلة جدًا.


ساعد استخدام مكتبة Evalcache في إجراء تعديلات على هذا الموقف.


 #!/usr/bin/env python3 #coding:utf-8 import sys import types from moviepy.editor import * import evalcache.lazyfile lazyhash = evalcache.LazyHash() lazyfile = evalcache.lazyfile.LazyFile() LazyVideoClip = lazyhash(VideoClip) VideoFileClip = lazyhash(VideoFileClip) AudioFileClip = lazyhash(AudioFileClip) CompositeVideoClip = lazyhash(CompositeVideoClip) concatenate_videoclips = lazyhash(concatenate_videoclips) @lazyfile("path") def lazy_write_videofile(path, clip): clip.write_videofile(path) source = VideoFileClip("source.mp4") music0 = AudioFileClip("music0.mp3") music1 = AudioFileClip("music1.mp3") music = music0 dur = 3 s0 = 1 s1 = 8 s2 = 16 part0 = source.subclip(s0, s0 + dur) part1 = source.subclip(s1, s1 + dur * 2).fl_time(lambda t: t * 2).set_duration(2) part2 = source.subclip(s2, s2 + dur * 4).fl_time(lambda t: t * 5).set_duration(2) clip = concatenate_videoclips([part0, part1, part2]) clip = clip.set_audio(music.set_duration(clip.duration)) lazy_write_videofile("part0.mp4", part0) lazy_write_videofile("part1.mp4", part1) lazy_write_videofile("part2.mp4", part2) lazy_write_videofile("part0_mus.mp4", part0.set_audio(music.set_duration(part0.duration))) lazy_write_videofile("part1_mus.mp4", part1.set_audio(music.set_duration(part1.duration))) lazy_write_videofile("part2_mus.mp4", part2.set_audio(music.set_duration(part2.duration))) if len(sys.argv) > 1 and sys.argv[1] == "compile": clip.lazy_write_videofile("clip.mp4", clip) 

ماذا يوجد هناك.


نحن نستخدم آليات التنفيذ غير المخزنة مؤقتًا ، حيث لا توجد رغبة أو حاجة للتعامل مع التخزين المؤقت للكائنات المتحركة. من خلال القيام بذلك ، نحصل على جميع فوائد الأشياء البطيئة لتتبع التغييرات في شجرة التنفيذ.


مكالمات مكتبة التفاف في lenificators:


 LazyVideoClip = lazyhash(VideoClip) VideoFileClip = lazyhash(VideoFileClip) AudioFileClip = lazyhash(AudioFileClip) CompositeVideoClip = lazyhash(CompositeVideoClip) concatenate_videoclips = lazyhash(concatenate_videoclips) 

باستخدام هذا البناء ، سننشئ الملفات:


 @lazyfile("path") def lazy_write_videofile(path, clip): clip.write_videofile(path) 

بعد الانتهاء من العمليات اللازمة في تسلسل الفيديو ، نكتب أجزاء من مقطعنا في ملفات منفصلة. مع أو بدون موسيقى:


 lazy_write_videofile("part0.mp4", part0) lazy_write_videofile("part1.mp4", part1) lazy_write_videofile("part2.mp4", part2) lazy_write_videofile("part0_mus.mp4", part0.set_audio(music.set_duration(part0.duration))) lazy_write_videofile("part1_mus.mp4", part1.set_audio(music.set_duration(part1.duration))) lazy_write_videofile("part2_mus.mp4", part2.set_audio(music.set_duration(part2.duration))) 

سيتم إعادة ترجمة هذه الملفات فقط عندما تتغير فروع التنفيذ المقابلة.


عند اكتمال النتيجة ، اجمع الأجزاء في ملف كبير باستخدام خيار "التحويل البرمجي":


 if len(sys.argv) > 1 and sys.argv[1] == "compile": clip.lazy_write_videofile("clip.mp4", clip) 

بدلاً من الاستنتاج:


يوضح هذا النص كيف ، بمساعدة مكتبة Evalcache ، يمكنك تسريع خوارزمية تفترض إنشاء الملف.
يسمح لك هذا النهج بتقليل الاعتماد على البرامج المتخصصة أو لتجنب كتابة منطق معقد للتجميع الانتقائي.


المراجع:


مشروع جيثب
مشروع Pypi

Source: https://habr.com/ru/post/ar430186/


All Articles