إذا قمت بتعريف دالة d2 قبل دالة d1 التي تستدعي d2 ثم غيرت d2 ، فإن d1 تستخدم التعريف القديم لـ d2.
أفترض أن هذا لأنه تم تجميعه مسبقًا ، ولكن ربما يجب أن يكون هناك ملاحظة تحذر من هذا؟ أم أنه من الممكن استبدال التعريف القديم بـ longjmp بالتعريف الجديد؟
(مهم في الغالب لـ REPL ، لأنني لا أقوم دائمًا بحمل كامل)
julia> function d2()
a
end
julia> function d()
d2()
end
julia> d()
in d: a not defined
julia> function d2()
b=2
end
julia> d()
in d: a not defined
julia> d2
Methods for generic function d2
d2() at prompt:2
julia> function d()
d2()
end
julia> d()
2
أعتقد أن السبب في ذلك هو إنشاء رمز d2()
عند تحديد الوظيفة ، لذا يتم حل طريقة d()
في ذلك الوقت. كما لاحظت ، يمكنك إعادة تعريف d2()
كما تم تعريفه في الأصل لجعله يعمل كما هو متوقع. من الناحية المثالية ، سنقوم تلقائيًا بإعادة تعريف أي شيء يعتمد على d()
عندما يتم تغييره على هذا النحو ، ولكن ليس لدينا أي من البيانات الوصفية في المكان الذي يسمح بذلك. أعتقد أنه يمكننا وضع تحذير حول هذا السلوك في الدليل. من الأفضل إصلاحه ، لكنني أعتقد أنه من الصعب بعض الشيء القيام به: - /
كنت أتمنى ألا يلاحظ أحد ذلك ، لكني أعتقد أن هذا لم يكن واقعيا بالنسبة لي :)
إنها أكثر متعة من ذلك ؛ يتيح لك حقًا رؤية JIT أثناء العمل ، حيث لا يتم حلها حتى التنفيذ:
julia> function f2()
a
end
julia> function f1()
f2()
end
julia> function f2()
2
end
julia> f1()
2
ومع ذلك ، أخشى أن يؤدي ذلك إلى بعض النتائج غير المتوقعة في REPL ، على الرغم من أنني لا أعرف حقًا أفضل طريقة للتعامل معها. على الرغم من أنني استخدمت خطأ لإظهار الاختلاف بطريقة دراماتيكية ، إلا أنه قد يحدث أيضًا إذا كنت أحاول رؤية تأثير تغيير معادلة داخلية أو ثابت!
هناك نوعان من المواقع التي قد تحتاج إلى تحديث عند تغيير الطريقة:
يمكن تحديث الأول فقط عن طريق تغيير جسم الوظيفة: يمكن تعديله في مكانه ، أو يمكن تحديث مواقع الاتصال بنشاط لاستدعاء موقع جديد ، أو يمكن استبدال جسم الوظيفة القديم بجذع ينتقل إلى الإصدار الجديد ، اختياريًا تصحيح موقع الاتصال. للتضمين ، نحتاج إلى تتبع المتصلين الذين قاموا بتضمين الوظيفة وإعادة JIT لهم.
كل ما يمكننا فعله حقًا هو تجاهل الكود ، لأنه حتى لو لم تكن الطريقة مضمنة ، فقد تعتمد أي وظيفة تستدعيها على سلوك النوع الذي يمكن أن يتغير إذا تغيرت الطريقة. هذا في الغالب للحالات التفاعلية ، لذا فإن إعادة تجميع الكود ليس بالأمر الضخم.
يتطلب نفس عمل المشكلة رقم 47.
المشكله. حسنًا ، نظرًا لأن الرد هو الذي تأثر في المقام الأول ، فإن القيام بالشيء الصحيح ببطء أمر جيد. في وقت التشغيل ، يجب ألا يبدأ هذا مطلقًا - لماذا يقوم شخص ما بتعريف شيء ما ثم إعادة تعريفه مرة أخرى إلا بشكل تفاعلي؟ إذا انتهى الحل بإحداث الكثير من النفقات العامة ، فربما يتم قلبه ، فيجب أن يكون الحل اختياريًا ويتم إجراؤه تلقائيًا في الرد؟
نحن بحاجة إلى توثيق أن هذا غير محدد حاليًا.
من الناحية الفنية ، هذا ليس خطأ ، إنه سلوك غير محدد. عندما تعيد تعريف طريقة ، يكون السلوك الناتج غير محدد. لذلك تستطيع جوليا أن تفعل ما تشاء ، بما في ذلك ما تفعله حاليًا. يعد توفير سلوك محدد جيدًا عند إعادة تعريف الطريقة ميزة وليست إصلاحًا للأخطاء. كما أنني لست مقتنعًا بأن هذه مشكلة الإصدار 1.0 لأن الانتقال من سلوك غير محدد إلى تقديم سلوك محدد جيدًا ليس تغييرًا جذريًا. يمكن تنفيذ ذلك في الإصدار 1.1 بدون كسر أي كود صالح v1.0.
كان Greg Clayton من فريق LLVM / LLDB التابع لشركة Apple لطيفًا بما يكفي لتوثيق كيفية استخلاص (مع مكتبات lldb ، مشروع فرعي من llvm) المعلومات اللازمة لتحديد تبعيات ثنائي من معلومات الرمز المضمنة (استيراد الرمز) ؛ بالإضافة إلى تلك الرموز التي تم تصديرها من خلال ثنائي (ضروري لبناء الرسم البياني الكامل للتبعية).
في 31 آذار (مارس) 2012 الساعة 11:02 مساءً ، كتب جايسون أتين:
أعزائي عشاق LLDB ،
أتساءل عما إذا كان بإمكاني استخدام مكتبة / مكتبات lldb لاستبدال كود معين يعمل على OSX والذي يعرض الآن قائمتين من الرموز - على غرار إخراج (dyldinfo -lazy_bind -exports
) ؛ على سبيل المثال ، أحتاج إلى سرد الرموز المستوردة والمصدرة بواسطة كائن أو حزمة ثنائية مشتركة. كنت آمل أنه باستخدام مكتبة lldb ، سأتمكن من استخدام نفس رمز العميل على OSX كما هو الحال في Linux. (تستخدم نسخة لينكس من الكود حاليًا libbfd و libdld لفعل الشيء نفسه ، لكن الأحدث لا يحصل على القليل من الحب / الصيانة).
أبحث من خلال include / lldb / ، حيث يبدو أن lldb ستحتاج إلى هذه المعلومات نفسها (قائمة الرموز المستوردة ، وقائمة الرموز المصدرة لملف Mach-O) لتعمل ، ولكن ليس من الواضح أي واجهة برمجة تطبيقات يجب استخدامها. جميع الاقتراحات / المؤشرات على رمز المثال في lldb ستكون موضع ترحيب!
شكرا لك.
جايسونفي حالة عدم وضوح ما يفعله dyldinfo ، فإليك مثال: (لكنني فقط بحاجة إلى أسماء الرموز ؛ وليس العناوين أو المقاطع أو الأقسام):
ملف $ / tmp / sample_bundle
/ tmp / sample_bundle: حزمة Mach-O 64 بت x86_64$ dyldinfo -lazy_bind -export / tmp / sample_bundle
معلومات الربط البطيئة (من جزء lazy_bind من معلومات dyld):
مقطع عنوان فهرس رمز dylib
__DATA __la_symbol_ptr 0x00001030 0x0000 مساحة الاسم المسطحة __mm_pop_chunk
__DATA __la_symbol_ptr 0x00001038 0x0015 مساحة الاسم المسطحة _dh_define
تصدير المعلومات (من trie):
0x000008A0 _C_ipair
0x00000920 _init_ipair
0x00000BC0 _C_iprot
0x00000C40 _C_ipi2
0x00000CC0 _C_ipi1
0x00001040 _K_ipair_R43808f40
0x00001160 _K_ipi1_R5cb4475d
0x00001260 _K_ipi2_R5cb4475d
0x00001360 _K_iprot_Rfc8fe739
0x00001460 _majver_ipair
0x00001464 _minver_ipair
في يوم الإثنين 2 أبريل 2012 الساعة 3:13 مساءً ، كتب جريج كلايتون [email protected] :
Yes you can do this with LLDB. If you load a binary and dump its symbol table, you will see the information you want. For symbols that are lazily bound, you can look for "Trampoline" symbols:
cd lldb/test/lang/objc/foundation
make
lldb a.out
(lldb) target modules dump symtab a.out
Symtab, file = .../lldb/test/lang/objc/foundation/a.out, num_symbols = 54:
Debug symbol
|Synthetic symbol
||Externally Visible
|||
Index UserID DSX Type File Address/Value Load Address Size Flags Name
------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------
[ 0] 0 D SourceFile 0x0000000000000000 Sibling -> [ 15] 0x00640000 /Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/main.m
[ 1] 2 D ObjectFile 0x000000004f79f1ca 0x0000000000000000 0x00660001 /Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/main.o
[ 2] 4 D Code 0x00000001000010f0 0x00000000000000c0 0x000e0000 -[MyString initWithNSString:]
[ 3] 8 D Code 0x00000001000011b0 0x0000000000000090 0x000e0000 -[MyString dealloc]
[ 4] 12 D Code 0x0000000100001240 0x00000000000000a0 0x000e0000 -[MyString description]
[ 5] 16 D Code 0x00000001000012e0 0x0000000000000020 0x000e0000 -[MyString descriptionPauses]
[ 6] 20 D Code 0x0000000100001300 0x0000000000000030 0x000e0000 -[MyString setDescriptionPauses:]
[ 7] 24 D Code 0x0000000100001330 0x0000000000000030 0x000e0000 -[MyString str_property]
[ 8] 28 D Code 0x0000000100001360 0x0000000000000050 0x000e0000 -[MyString setStr_property:]
[ 9] 32 D Code 0x00000001000013b0 0x0000000000000040 0x000f0000 Test_Selector
[ 10] 36 D Code 0x00000001000013f0 0x0000000000000130 0x000f0000 Test_NSString
[ 11] 40 D Code 0x0000000100001520 0x0000000000000120 0x000f0000 Test_MyString
[ 12] 44 D Code 0x0000000100001640 0x00000000000001b0 0x000f0000 Test_NSArray
[ 13] 48 D Code 0x00000001000017f0 0x00000000000000e1 0x000f0000 main
[ 14] 56 D X Data 0x0000000100002680 0x0000000000000000 0x00200000 my_global_str
[ 15] 58 D SourceFile 0x0000000000000000 Sibling -> [ 19] 0x00640000 /Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/my-base.m
[ 16] 60 D ObjectFile 0x000000004f79f1ca 0x0000000000000000 0x00660001 /Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/my-base.o
[ 17] 62 D Code 0x00000001000018e0 0x0000000000000020 0x000e0000 -[MyBase propertyMovesThings]
[ 18] 66 D Code 0x0000000100001900 0x000000000000001f 0x000e0000 -[MyBase setPropertyMovesThings:]
[ 19] 82 Data 0x0000000100002000 0x0000000000000460 0x000e0000 pvars
[ 20] 83 ObjCIVar 0x0000000100002518 0x0000000000000148 0x001e0000 MyBase.propertyMovesThings
[ 21] 84 X Data 0x0000000100002660 0x0000000000000008 0x000f0000 NXArgc
[ 22] 85 X Data 0x0000000100002668 0x0000000000000008 0x000f0000 NXArgv
[ 23] 86 X ObjCClass 0x00000001000024d8 0x0000000000000028 0x000f0000 MyBase
[ 24] 87 X ObjCClass 0x0000000100002460 0x0000000000000028 0x000f0000 MyString
[ 25] 88 X ObjCIVar 0x0000000100002510 0x0000000000000008 0x000f0000 MyString._desc_pauses
[ 26] 89 X ObjCIVar 0x0000000100002508 0x0000000000000008 0x000f0000 MyString.date
[ 27] 90 X ObjCIVar 0x0000000100002500 0x0000000000000008 0x000f0000 MyString.str
[ 28] 91 X ObjCMetaClass 0x00000001000024b0 0x0000000000000028 0x000f0000 MyBase
[ 29] 92 X ObjCMetaClass 0x0000000100002488 0x0000000000000028 0x000f0000 MyString
[ 30] 97 X Data 0x0000000100002678 0x0000000000000008 0x000f0000 __progname
[ 31] 98 X Data 0x0000000100000000 0x00000000000010b0 0x000f0010 _mh_execute_header
[ 32] 99 X Data 0x0000000100002670 0x0000000000000008 0x000f0000 environ
[ 33] 101 X Data 0x0000000100002680 0x0000000000000000 0x000f0000 my_global_str
[ 34] 102 X Code 0x00000001000010b0 0x0000000000000040 0x000f0000 start
[ 35] 103 Trampoline 0x0000000100001938 0x0000000000000006 0x00010200 NSLog
[ 36] 104 X Undefined 0x0000000000000000 0x0000000000000000 0x00010400 OBJC_CLASS_$_NSArray
[ 37] 105 X Undefined 0x0000000000000000 0x0000000000000000 0x00010200 OBJC_CLASS_$_NSAutoreleasePool
[ 38] 106 X Undefined 0x0000000000000000 0x0000000000000000 0x00010400 OBJC_CLASS_$_NSDate
[ 39] 107 X Undefined 0x0000000000000000 0x0000000000000000 0x00010400 OBJC_CLASS_$_NSObject
[ 40] 108 X Undefined 0x0000000000000000 0x0000000000000000 0x00010200 OBJC_CLASS_$_NSString
[ 41] 109 X Undefined 0x0000000000000000 0x0000000000000000 0x00010400 OBJC_METACLASS_$_NSObject
[ 42] 110 X Undefined 0x0000000000000000 0x0000000000000000 0x00010400 __CFConstantStringClassReference
[ 43] 111 X Undefined 0x0000000000000000 0x0000000000000000 0x00010100 _objc_empty_cache
[ 44] 112 X Undefined 0x0000000000000000 0x0000000000000000 0x00010100 _objc_empty_vtable
[ 45] 113 Trampoline 0x000000010000193e 0x0000000000000006 0x00010300 exit
[ 46] 114 Trampoline 0x0000000100001920 0x0000000000000006 0x00010100 objc_getProperty
[ 47] 115 Trampoline 0x0000000100001926 0x0000000000000006 0x00010100 objc_msgSend
[ 48] 116 Trampoline 0x000000010000192c 0x0000000000000006 0x00010100 objc_msgSendSuper2
[ 49] 117 X Undefined 0x0000000000000000 0x0000000000000000 0x00010100 objc_msgSend_fixup
[ 50] 118 Trampoline 0x0000000100001932 0x0000000000000006 0x00010100 objc_setProperty
[ 51] 119 Trampoline 0x0000000100001944 0x0000000000000006 0x00010300 printf
[ 52] 120 Trampoline 0x000000010000194a 0x0000000000000006 0x00010300 usleep
[ 53] 121 X Undefined 0x0000000000000000 0x0000000000000000 0x00010300 dyld_stub_binder
(lldb)
All lazily bound symbols will have type Trampoline:
[ 45] 113 Trampoline 0x000000010000193e 0x0000000000000006 0x00010300 exit
[ 46] 114 Trampoline 0x0000000100001920 0x0000000000000006 0x00010100 objc_getProperty
[ 47] 115 Trampoline 0x0000000100001926 0x0000000000000006 0x00010100 objc_msgSend
[ 48] 116 Trampoline 0x000000010000192c 0x0000000000000006 0x00010100 objc_msgSendSuper2
[ 50] 118 Trampoline 0x0000000100001932 0x0000000000000006 0x00010100 objc_setProperty
[ 51] 119 Trampoline 0x0000000100001944 0x0000000000000006 0x00010300 printf
[ 52] 120 Trampoline 0x000000010000194a 0x0000000000000006 0x00010300 usleep
The other symbols that are exernal are marked with an "X" (which is a boolean flag on each symbol).
The symbols can be accessed via the SBModule:
size_t
SBModule::GetNumSymbols ();
lldb::SBSymbol
SBModule::GetSymbolAtIndex (size_t idx);
And then you can get the symbol type from each SBSymbol:
SymbolType
SBSymbol::GetType ();
I just added the ability to see if a symbol is externally visible:
% svn commit
Sending include/lldb/API/SBSymbol.h
Sending scripts/Python/interface/SBSymbol.i
Sending source/API/SBSymbol.cpp
Transmitting file data ...
Committed revision 153893.
bool
SBSymbol::IsExternal();
So your flow should be:
SBDebugger::Initialize();
SBDebugger debugger(SBDebugger::Create());
SBTarget target (debugger.CreateTarget (const char *filename,
const char *target_triple,
const char *platform_name,
bool add_dependent_modules,
lldb::SBError& error));
SBFileSpec exe_file_spec (filename);
SBModule exe_module (target.FindModule(exe_file_spec));
if (exe_module.IsValid()
{
const size_t num_symbols = exe_module. GetNumSymbols();
for (size_t i=0; i<num_symbols; ++i)
{
SBSymbol symbol (exe_module. GetSymbolAtIndex(i));
if (symbol.IsExternal())
{
}
if (symbol.GetType() == lldb::eSymbolTypeTrampoline)
{
}
}
}
> _______________________________________________
> lldb-dev mailing list
> [email protected]
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
في يوم الإثنين 2 أبريل 2012 الساعة 4:05 مساءً ، كتب جريج كلايتون [email protected] :
A quick clarification on the args to CreateTarget:
"filename" is just a full path to the local object file you want to observer. "target_triple" is your <arch>-<vendor>-<os>, or something like "x86_64-apple-darwin" or "i386-pc-linux" and can be NULL if the file is only a single architecture. "platform_name" can be NULL. "add_dependent_modules" should be false, since you are only interested in seeing the one object file itself, an SBError instance should be created and passed in.
مناقشة قائمة مطوري هنا: https://groups.google.com/forum/؟fromgroups=#!topic/julia -dev / snnGKJul4vg.
هذا هو تجريف خيط قديم بشكل مثير للدهشة ، لكنني أدركت أنني ربما أتعامل مع حواف هذه المشكلة مع كود قياس سرعة الشفرة الخاص بي. قمت مرارًا بتكرار ملفات Core.include()
التي تحتوي على وظيفتين ، listTests()
و runTests()
. ثم اتصل بكل بساطة بـ listTests()
و runTests()
، وبذلك أعيد تعريفهما ثم استدعائهما في كل مرة أقوم فيها بتحميل ملف معياري جديد. نظرًا لأنني لا أقوم بإعادة تعريف وظائف المستوى الثاني ، لا أعتقد أنني سأواجه المشكلات المدرجة هنا ، ولكن هل إعادة تعريف أشياء مثل هذه طريقة سيئة للاستمرار في التحميل في ملفات متعددة باستخدام نفس "واجهة برمجة التطبيقات"؟
قد يكون من الأفضل تضمينها في وحدة بشكل متكرر ، لكني أدرك أن هذه الصعوبات تتعارض مع مشكلة الوحدة المجهولة التي أثيرت أيضًا في قائمة المطورين. في هذه الحالة ، قد يكون الأمر جيدًا ، نظرًا لأنه يمكنك فقط تحديد نفس الوحدة عدة مرات وتجاهل التحذير الذي ينبعث.
ربما يكون موضوعًا قديمًا ، ولكنه وثيق الصلة كما كان دائمًا.
ربما طريقة أخرى هي استخدام evalfile
وجعل الملف "يعرض" مجموعة من الدوال. ما هي مشكلة الوحدة المجهولة؟
كنت أشير إلى هذا: https://github.com/JuliaLang/julia/issues/3661.
أي شخص لديه أفكار إضافية حول استراتيجيات التنفيذ؟ كنت أفكر في ترميز مخطط بسيط يحافظ على رسم بياني للمكالمات المقلوبة يتم تحديثه كلما تم إنشاء طريقة جديدة (بناءً على AST غير المحسن). ثم يمشي في هذا الرسم البياني عندما يتم إعادة تعريف طريقة ما ، ويزيل النسخة المترجمة لكل من أحفاد الوظيفة المعاد تعريفها.
هذا نهج معقول مثل أي نهج يمكن تجربته. إذا كنت تشعر بالحافز للقيام بذلك ، فسأقول تفضل ودعنا نرى ما سيحدث!
ماذا يحدث إذا أدى _إعدام المستدعي إلى إعادة تجميع المتصل؟
أسأل لأنني أدركت متأخراً أن حل هذه المشكلة قد يكون له عواقب مثيرة للاهتمام تتجاوز تجربة المستخدم في REPL: فقد يسمح بالإجابة النهائية لمشكلة البرمجة الوصفية ، وهي إنشاء وظائف "مرحلية" فعالة. كخلفية لأولئك الذين قد لا يعرفون: يتم تنفيذ بعض الوظائف حاليًا عن طريق البرمجة الوصفية ، لا سيما تلك التي يعتمد فيها جانب من جوانب الخوارزمية على أنواع المدخلات بطريقة غير بديهية - المثال الأساسي هو الذي فيه الرقم من الحلقات في جسم الوظيفة تساوي أبعاد المصفوفة. الطريقة التي نتعامل بها عادة مع هذا هي تحديد الوظيفة بشكل صريح ، على سبيل المثال ، الأبعاد 1 و 2 ، ثم لدينا غلاف يشبه ما يلي:
_method_cache = Dict()
function myfunction(A::AbstractArray)
N = ndims(A)
if !haskey(_method_cache, N)
func = eval(<an expression that generates the function definition for N dimensions>)
_method_cache[N] = func
else
func = _method_cache[N]
end
return func(A)
end
لذلك في المرة الأولى التي يتم فيها تنفيذ myfunction
لمصفوفة رباعية الأبعاد ، يقوم أولاً بتعريف إصدار خاص بأربعة أبعاد ، ويضيفها إلى _method_cache
، ثم يقيّم الوظيفة الجديدة على الإدخال. في المكالمات المستقبلية إلى myfunction
باستخدام مصفوفة رباعية الأبعاد ، يقوم فقط باسترداد التعريف من القاموس وتقييمه. _method_cache
هو نوع من "جدول أسلوب الظل" بالتوازي مع جدول الأسلوب الداخلي الخاص بجوليا ، وهو جدول يستخدم فقط لهذه الوظيفة المحددة. (للحفاظ على خصوصيتها ، يتم تغليفها عادةً بـ let
.)
بينما يعمل النهج في هذا المثال جيدًا للهيئات الوظيفية التي تستغرق بعض الوقت للتنفيذ ، إلا أنه ليس مناسبًا تمامًا للوظائف التي يتم تنفيذها في وقت أقل مما هو مطلوب للبحث في القاموس ، وهو سيء بشكل خاص للوظائف التي تريد أن تكون قادرة على مضمنة.
قد تكون أفضل طريقة للقيام بذلك هي ما يلي:
function myfunction(A::AbstractArray)
bodyexpr = <an expression for the body of the function specific for N dimensions>
f = <strong i="17">@eval</strong> begin
function myfunction(A::$(typeof(A)))
$bodyexpr
end
end
return f(A)
end
هنا ، يؤدي تنفيذ myfunction
إنشاء إصدار _أكثر تحديدًا_ من myfunction
لأنواع الإدخال المحددة هذه. الرمز الذي تم تجميعه بعد أن يصبح هذا التعريف الجديد متاحًا سيستخدم هذا الإصدار الجديد عند الاقتضاء ؛ يصبح الإصدار أعلاه "احتياطيًا" عامًا لتلك الحالات التي لم تحدد فيها بالفعل شيئًا أكثر تحديدًا. وبالتالي ، ستكون هذه طريقة لإنشاء وظائف مرحلية تستغل آليات جدول الأساليب الداخلية الخاصة بجوليا ، وبالتالي تسمح لأحد بتوليد رمز فعال.
حاليًا ، هذا لا يعمل لسبب واحد حاسم: كل ما يسمى myfunction
تم تجميعه بالفعل ، لذلك لا يعرف عن التعريف الجديد. وبالتالي ، سينشئ هذا المتصل المعين دائمًا إصدارًا جديدًا جديدًا myfunction
باستخدام eval
، والذي سيكون بطيئًا للغاية.
لذا ستكون الحيلة هي إعادة ترجمة المتصل ، لكن لاحظ أن هذا يجب أن يحدث - بينما يكون في منتصف التنفيذ -. ماذا سيحدث؟
أنظر أيضا # 5395.
هناك مشكلة مرتبطة بأنواع مجردة لا تتضمن في الواقع إعادة تعريف الطريقة ولكنها تحتاج إلى معالجة مماثلة. يعتبر:
abstract A
immutable B <: A; end
immutable C <: A; end
g(x::Vector{A}) = f(x[1])
f(::B) = 1
g(A[B()])
f(::C) = 0.5
g(A[C()])
السطر الأخير يعطي 4602678819172646912
. نحتاج إلى التخلص من الكود الخاص بـ g
لأن نوع الاستدلال لـ f(::A)
لم يعد صالحًا.
نعم ، هذا واضح تمامًا. نحن نعلم أن استبدال الطرق هو حالة خاصة واحدة فقط. لكنها تتضمن دائمًا تعريفات طرق جديدة.
يبدو أن الوضع الحالي يمكن أن يكون غامضًا إلى حد ما منذ ذلك الحين
f() = x()
x() = 1
println(f())
x() = 2
println(f())
يعطي
1
1
في حين
g() = y()
precompile(g, ())
y() = 1
println(g())
y() = 2
println(g())
يعطي
1
2
يبدو أنه يمكن استخدام الحالة اللاحقة كحل بديل لمحاكاة إعادة تجميع المتصل (أعلم أنها ليست إعادة تجميع فعلاً).
لدي شعور بأنني على وشك أن أقول شيئًا غبيًا ، لكن ألا يمكن التخلص من هذه المشكلة بمستوى واحد من المراوغة؟ بدلاً من الترميز الثابت لعنوان دالة ، ابحث عنه من موقع ثابت واستدع هذا العنوان. ألن يكون لهذا أداء مشابه لوظائف C ++ أو Java الافتراضية؟ يمكنك بعد ذلك التعليق على الوظائف للحصول على عنوان ثابت أو ديناميكي ، والحصول على تحذير / خطأ عند محاولة إعادة تعريف وظيفة بعنوان ثابت. يمكن أن يكون هناك مفتاح لتعيين سلوك الوظيفة الافتراضي. أنا جديد على اللغة وغير معتاد تمامًا على قاعدة الشفرة ، ولكن إذا كان هذا يبدو ممكناً ، أفترض أنني يمكن أن أعطيها دفعة.
@ omer4d إحدى مشكلات هذه الفكرة هي أن جوليا تقوم
يمكن أن تكون مضمنة فقط في العناوين الثابتة ، مثل C ++. لا ينبغي أن يسبب هذا أي إزعاج.
لن يتأثر الأشخاص الذين لا يهتمون بالتطوير التفاعلي على الإطلاق ، لأن السلوك الافتراضي سيكون استخدام العناوين الثابتة لجميع الوظائف.
يمكن للأشخاص الذين لا يهتمون بالأداء ولكنهم يريدون التطوير التفاعلي استخدام مفتاح لجعل عناوين الوظائف ديناميكية بشكل افتراضي.
يمكن للأشخاص الذين يرغبون في التفاعل والأداء أن يقوموا فقط بالتعليق على الوظائف ذات الصلة ، والتي لا ينبغي أن تتطلب الكثير من العمل ، نظرًا لأن التضمين مناسب فقط للوظائف القصيرة منخفضة المستوى التي يتم استدعاؤها كثيرًا.
ربما يمكن تعيين السلوك الافتراضي لكل وحدة.
أعتقد أن هناك عدة أسباب تجعل هذا النهج غير قابل للتطبيق. أول،
تعد التعليقات التوضيحية مصدر إزعاج حقًا ، لا سيما عندما تكون ضرورية للاختراق
حول تفاصيل التنفيذ مثل هذا. إذا تم استخدام التعليقات التوضيحية لحل 2
أو 3 مشاكل ، تبدأ في التراكم بشكل ملحوظ. ثانيًا ، لا يوجد
طريقة جيدة لاختيار التعليق التوضيحي المناسب لوظيفة ما. لا يوجد
الاتصال بين ما إذا كنت تريد شيئًا مضمّنًا وما إذا كنت كذلك
تطويره بشكل تفاعلي. ثالثًا ، اكتب الخصومات في وظائف أخرى
قد تحتاج إلى التغيير ، لذا فهي ليست مجرد مواقع اتصال. في الحقيقة نحن حاليا
استخلاص معلومات أقل مما يمكننا صنع الأشياء
بأمان في مواجهة هذه المشكلة.
حسنًا ، بصفتك شخصًا يقوم بمعظم أعماله بلغات مع عشرات الكلمات الرئيسية المؤهلة وإعادة ترجمة يدوية متكررة ، فإن الاضطرار أحيانًا إلى تأهيل وظيفة أو اثنتين وإعادة التجميع بعد بضع دورات من التطوير التفاعلي لا يبدو سيئًا للغاية ، ولكن هذا أنا فقط . لا أعرف ما يكفي لتناول النقطة الثالثة ، لذلك سأستقيل. أعتقد أنه من المؤسف أن مثل هذا الحل غير قابل للتطبيق ، لأن إعادة التجميع تعني أنه إذا كان جذر شجرة استدعاء الوظيفة المعدلة يحتوي على لعبة أو حلقة رسوم متحركة ، فسيلزم إنهاؤها وإعادة تشغيلها. = (
JeffBezanson ربما سأكون أكثر اهتمامًا بالقضية السهلة ، على الأقل في البداية. لا يهمني أنه يتم تحديث الكثير من التعليمات البرمجية قيد التشغيل ، على عكس الأشياء التي يتم الوصول إليها من خلال eval
(على سبيل المثال ، تم إدخالها في موجه REPL). في النهاية ، سيكون من المهم أيضًا الحصول على الإصدار الصحيح من display
عند إعادة تعريفه. لكنني أعتقد أن ذلك سيقربنا بسرعة من الحصول على تجميعات تدريجية.
لقد اندهشت قليلاً لمعرفة هذه المشكلة ، ليس لأنني أعتقد أنه من السهل التعامل معها ، ولكن لأن ما يلي يعمل كما هو متوقع.
julia> f(a, b) = a + b
f (generic function with 1 method)
julia> g(args...) = f(args...)
g (generic function with 1 method)
julia> g(1, 2)
3
julia> f(a::Int, b::Int) = a - b
f (generic function with 2 methods)
julia> g(1, 2)
-1
تحرير: في الواقع هذا يبدو كحالة خاصة لإدخال Vararg ..... هل هذا يعني أنه يتم إعادة ترجمة دالة vararg في كل مرة يتم استدعاؤها؟ أم أنها ذكية بما يكفي لإعادة الترجمة عند الضرورة فقط؟ وهل من الممكن التعامل مع الوظائف الأخرى بنفس الطريقة؟
julia> f(a, b) = a + b
f (generic function with 1 method)
julia> g(a, b) = f(a, b)
g (generic function with 1 method)
julia> g(1, 2)
3
julia> f(a::Int, b::Int) = a - b
f (generic function with 2 methods)
julia> g(1, 2)
3
في الواقع ، ترجع الدالة النتيجة الصحيحة لكن @code_typed
ترجع نتيجة خاطئة .....
julia> f(a, b) = a + b
f (generic function with 1 method)
julia> g(args...) = f(args...)
g (generic function with 1 method)
julia> g(1, 2)
3
julia> <strong i="7">@code_typed</strong> g(1, 2)
1-element Array{Any,1}:
:($(Expr(:lambda, Any[:(args::(top(apply_type))(Vararg,Any)::Any::Any)], Any[Any[],Any[Any[:args,(Int64,Int64),0]],Any[]], :(begin # none, line 1:
return (top(box))(Int64,(top(add_int))((top(tupleref))(args::(Int64,Int64),1)::Int64,(top(tupleref))(args::(Int64,Int64),2)::Int64))
end::Int64))))
julia> f(a::Int, b::Int) = a - b
f (generic function with 2 methods)
julia> g(1, 2)
-1
julia> <strong i="8">@code_typed</strong> g(1, 2)
1-element Array{Any,1}:
:($(Expr(:lambda, Any[:(args::(top(apply_type))(Vararg,Any)::Any::Any)], Any[Any[],Any[Any[:args,(Int64,Int64),0]],Any[]], :(begin # none, line 1:
return (top(box))(Int64,(top(add_int))((top(tupleref))(args::(Int64,Int64),1)::Int64,(top(tupleref))(args::(Int64,Int64),2)::Int64))
end::Int64))))
و
julia> f(a, b) = a + b
f (generic function with 1 method)
julia> g(args...) = f(args...)
g (generic function with 1 method)
julia> g(1, 2)
3
julia> f(a::Int, b::Int) = a - b
f (generic function with 2 methods)
julia> g(1, 2)
-1
julia> <strong i="12">@code_typed</strong> g(1, 2)
1-element Array{Any,1}:
:($(Expr(:lambda, Any[:(args::(top(apply_type))(Vararg,Any)::Any::Any)], Any[Any[],Any[Any[:args,(Int64,Int64),0]],Any[]], :(begin # none, line 1:
return (top(box))(Int64,(top(sub_int))((top(tupleref))(args::(Int64,Int64),1)::Int64,(top(tupleref))(args::(Int64,Int64),2)::Int64))
end::Int64))))
هل سيعمل على فهرسة طرق الوظائف (أو فقط أنواع الوظائف / الكائنات نفسها) برقم يتغير في كل مرة يتم فيها تعيين أي شيء وبالتالي يصبح قادرًا على التحقق مما إذا كان الرقم المخزن مع الوظيفة المترجمة (المتصل) (أي استخدام البنية الجديدة من الوظائف ، حفظ هذه الأرقام كحقل وما إلى ذلك) لا يزال يطابق الرقم "الحالي" في الوظيفة التي تم تضمينها (تسمى)؟
(بدون عقوبة أداء كبيرة بالطبع)
وفي حالة التغيير ، فكر في تجميع الإصدار الجديد أو إكماله عن طريق استدعاء صريح.
سيؤدي ذلك إلى نقل تأثير الأداء إلى وقت التشغيل (وسيكون في كل مكان) ، وهو أمر غير مرغوب فيه. ما نحتاجه هو تتبع شبكة التبعيات وإعادة تجميع أي شيء قد يتأثر عند إعادة تعريف الطريقة جزئيًا. من المحتمل أن يكون الأمر ممكنًا ، إنه مجرد ألم "هائل".
لا أعرف ما إذا كان حل هذه المشكلة يمكن تعميمه بسهولة على وحدات الماكرو ، ولكن إذا كان الأمر كذلك ، فسيكون ذلك أمرًا رائعًا.
لذلك يجب على المرء أن يسير في الاتجاه الآخر ويخزن جميع الطرق التي تضمنت الوظيفة وعند التغيير يعيد تجميعها. (بالطبع التحقق من التنفيذ الحالي ، إلخ)
المشاكل الصعبة هنا هي:
أثناء العمل على حل المشكلة ، أشعر بالفضول فيما إذا كان من الممكن وفكرة جيدة إضافة علامة إلى كل وظيفة تم تعيينها إذا (وفقط إذا) تم استخدام الوظيفة المحددة بأي من الطرق العليا ( inlining إلخ) لإصدار تحذير من إعادة تعريف طريقة مضمنة. (على غرار الطريقة التي يعمل بها التحذير الغامض)
إذا لم تكن هناك طريقة أفضل لحفظ العلم ، فربما مرة أخرى باستخدام الهيكل الجديد للطرق / الوظائف في جوليا 0.5
أصبح من الأسهل الآن النقر على هذا في الرد وربما يجب توثيق هذا السلوك للخريطة؟
julia> function f(x)
1
end
f (generic function with 1 method)
julia> map(f, 1:10)
10-element Array{Int64,1}:
1
1
1
1
1
1
1
1
1
1
julia> function f(x)
2
end
WARNING: Method definition f(Any) in module Main at REPL[9]:2 overwritten at REPL[11]:2.
f (generic function with 1 method)
julia> map(f, 1:10)
10-element Array{Int64,1}:
1
1
1
1
1
1
1
1
1
1
هذا لا يزال مجرد فانيلا # 265. أعتقد أنك ستقدر أن هذا سيتم إصلاحه قريبًا في v0.6-dev :)
vtjnash هل هناك أي أداء وقت تشغيل أو مقايضة الذاكرة؟
يتطلب القليل من الذاكرة (140 ميجابايت -> 170 ميجابايت) ، ولكن لا ينبغي أن يكون له تأثير كبير على الأداء (التجميع أو وقت التشغيل). وأنا لم أحاول الكثير من التحسين حتى الآن.
العروض التوضيحية حتى الآن ممتعة:
julia> f() = 1
f (generic function with 1 method)
julia> function g(x)
<strong i="7">@eval</strong> f() = $x # this is the correct way to write `global f() = x` (which should be a syntax error, but isn't currently)
return @eval(f)() # use `eval` to hide the value from optimization / inlining, but the call is not inside eval
end
g (generic function with 1 method)
julia> g(2)
WARNING: Method definition f() in module Main at REPL[1]:1 overwritten at REPL[2]:2.
1
julia> g(3)
WARNING: Method definition f() in module Main at REPL[2]:2 overwritten at REPL[2]:2.
2
julia> g(4)
WARNING: Method definition f() in module Main at REPL[2]:2 overwritten at REPL[2]:2.
3
هل السبب في عدم إرجاع 2 ، 3 ، 4 يرجع إلى الترتيب الذي يحدث فيه تجميع g
مقابل التنفيذ الذي يعيد تعريف f
؟
هذا صحيح تقريبًا. لاحظ أن دلالات اللغة لا تحدد التجميع ، لذلك من الأصح القول أن الترتيب الذي يتم فيه تفسير g
مقابل الوقت الذي يصبح فيه إعادة تعريف f
مرئيًا للمترجم.
حسنًا ، إليك عرضًا تجريبيًا ممتعًا آخر يعيد تعريف العنصر البدائي +
للاحتفاظ بحساب مقدار استخدامه:
julia> add_ctr = UInt(0)
0x0000000000000000
julia> Base.:+(a::Int, b::Int) = (global add_ctr += 1; Core.Intrinsics.add_int(a, b))
julia> add_ctr
0x0000000000000016
julia> last = 0;
julia> println(Int(add_ctr - last)); last = add_ctr;
287
julia> println(Int(add_ctr - last)); last = add_ctr;
17
غش هذا الشخص: لا أعتقد أن Base تستخدمه على الإطلاق +
، لذا لم يكن هناك أي شيء لإعادة تجميعه. أعد تحديد وظيفة حقيقية ، مثل svd
، والتي تعلم أنه يجب استدعاءها 100 مرة على الأقل قبل ظهور REPL. ثم سننبهر.
إن فرص إعادة التشغيل المباشر للشفرة للتنميط / التتبع تدهشني.
في الواقع. وها أنا كنت على وشك شراء لوحة مفاتيح جديدة ، لأن التسلسل Ctrl-D; julia<Enter>
أوشك على التلف. يبدو أنني قد لا أضطر إلى ذلك.
قد يكون وضع ملاحظات الإصدار في ملاحظات الإصدار أمرًا غامضًا بعض الشيء ، ولكن يجب الإشارة في مكان ما إلى أن الفهم أصبح الآن بناء جملة لـ collect
-ing a Generator
(على عكس شيء ربما على مستوى التحليل) في 0.4؟ - @which
لا يعمل هناك)؟ هذا المثال ، على غرار vchuravy أعلاه ، هو نوع من مسكتك حتى مع الأخذ في الاعتبار أن كل وظيفة هي الآن نوع في 0.5:
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.5.0-rc3+0 (2016-08-22 23:43 UTC)
_/ |\__'_|_|_|\__'_| |
|__/ | x86_64-linux-gnu
julia> f(x) = 1
f (generic function with 1 method)
julia> [f(x) for x in 1:5]
5-element Array{Int64,1}:
1
1
1
1
1
julia> f(x) = 2
WARNING: Method definition f(Any) in module Main at REPL[1]:1 overwritten at REPL[3]:1.
f (generic function with 1 method)
julia> [f(x) for x in 1:5]
5-element Array{Int64,1}:
1
1
1
1
1
julia> <strong i="9">@which</strong> [f(x) for x in 1:5]
collect(itr::Base.Generator) at array.jl:295
ليس صحيح تماما؟
مفيد للإصلاح رقم 265
هل هذا ثابت حقا 😲
هل مازال هذا الحل مخططًا ليتم نقله إلى 0.5.x؟
لا.
@ rapus95 ، هذا تغيير جائر للغاية ، وقد
يسعدني جدًا أن أرى تقدمًا في هذه المسألة! سيكون من الرائع لو سمح هذا أيضًا للمترجم بتحسين الحالة الموضحة في https://groups.google.com/forum/#!topic/julia -users / OBs0fmNmjCU.
نجاح باهر. يا لها من لحظة عظيمة!
اهلا ياجماعة!
هل هناك أي إمكانية لدعم هذا الإصلاح إلى 0.5 سلسلة؟ أم أنها تعمل فقط فيما سيصبح 0.6؟
هذا تغيير جذري وسيكون متاحًا فقط في 0.6
من الصعب المبالغة في تقدير مدى روعة إصلاح هذا الأمر. تموت العادات القديمة بصعوبة لذلك أقوم أحيانًا بإعادة تشغيل و / أو إعادة بناء جوليا دون داع ، لكن عندما أتذكر أنها تغير قواعد اللعبة بالكامل لإصلاح المشكلات.
التعليق الأكثر فائدة
نجاح باهر. يا لها من لحظة عظيمة!