2010-03-14 15 views
29

Tôi đang lấy dữ liệu từ web và tôi có một số quy trình của trình thu thập dữ liệu chạy song song.Có an toàn khi đưa đầu ra của một số quy trình song song vào một tệp bằng cách sử dụng >> không?

Tôi muốn đầu ra của từng quy trình này kết thúc trong cùng một tệp. Miễn là dòng văn bản vẫn còn nguyên vẹn và không bị lẫn lộn với nhau, thứ tự của các dòng không quan trọng. Trong UNIX, tôi có thể chỉ cho đầu ra của mỗi tiến trình vào cùng một tệp bằng toán tử >> không?

+0

* InRe: Đóng phiếu bầu * Cách tôi thấy "Hoạt động Foo có an toàn để sử dụng đồng thời trong ngôn ngữ Bar không?" là một câu hỏi lập trình mỗi lần. Trong trường hợp này Foo là đường dẫn đầu vào cho std [in, err] và Bar là một số shell unix. Phải nói rằng tôi nghĩ rằng nó nên ở lại. – dmckee

Trả lời

24

No. Không đảm bảo rằng các đường sẽ vẫn nguyên vẹn. Họ có thể trở nên lộn xộn.

Từ tìm kiếm dựa trên câu trả lời của liori tôi thấy this:

Viết yêu cầu của {} PIPE_BUF byte hoặc ít hơn thì không được xen kẽ với các dữ liệu từ các quá trình khác làm ghi trên cùng một đường ống. Các ký tự lớn hơn {PIPE_BUF} byte có thể có dữ liệu xen kẽ, trên các đường biên tùy ý, với các quy trình khác viết, có hay không cờ O_NONBLOCK của các cờ trạng thái tệp được thiết lập.

Vì vậy, các dòng dài hơn {PIPE_BUF} byte không được bảo đảm nguyên vẹn.

+0

+1 Ha, tôi không thể tìm thấy báo giá thích hợp :-) – liori

+1

Chỉ cần làm rõ - trường hợp này chỉ dành cho đường ống, kể cả ống có tên (còn gọi là tệp FIFO). Nó không áp dụng cho các loại tệp khác, trong đó tình huống có khả năng ít được đảm bảo hơn không phải viết xen kẽ. – CivFan

1

Tóm lại, không. >> không tôn trọng nhiều quy trình.

3

Bạn cần phải đảm bảo rằng bạn đang viết toàn bộ các dòng trong các thao tác ghi đơn (vì vậy nếu bạn đang sử dụng một dạng stdio nào đó, bạn sẽ cần đặt nó cho dòng đệm trong ít nhất độ dài của dòng dài nhất mà bạn có thể xuất ra.) Vì shell sử dụng O_APPEND cho chuyển hướng >> thì tất cả các ghi của bạn sẽ tự động thêm vào tệp mà không có thêm hành động nào từ phía bạn.

2

Sử dụng các tệp tạm thời và nối chúng lại với nhau. Đó là cách an toàn duy nhất để làm những gì bạn muốn làm, và sẽ (có thể) là mất hiệu suất không đáng kể theo cách đó. Nếu hiệu suất thực sự là một vấn đề, hãy thử đảm bảo rằng thư mục/tmp của bạn là một hệ thống tập tin dựa trên RAM và đặt các tệp tạm thời của bạn ở đó. Bằng cách đó các tập tin tạm thời được lưu trữ trong RAM thay vì trên một ổ đĩa cứng, do đó, đọc/ghi chúng là gần như ngay lập tức.

+0

Tệp tạm thời là một ý tưởng hay. –

6

Nói chung, không. Trên Linux, điều này có thể, miễn là hai điều kiện được đáp ứng: mỗi dòng được viết trong một thao tác, và dòng không dài hơn PIPE_SIZE (thường là PAGE_SIZE, thường là 4096). Nhưng ... tôi sẽ không tin vào điều đó; hành vi này có thể thay đổi.

Tốt hơn nên sử dụng một số loại cơ chế ghi nhật ký thực, như syslog.

0

Ngoài ý tưởng sử dụng tệp tạm thời, bạn cũng có thể sử dụng một số loại quy trình tổng hợp, mặc dù bạn vẫn sẽ cần phải đảm bảo viết của mình là nguyên tử.

Hãy suy nghĩ Apache2 bằng cách ghi nhật ký đường ống (với thứ gì đó như trải rộng ở đầu kia của đường ống nếu bạn cảm thấy tham vọng). Đó là cách tiếp cận cần thiết, với nhiều luồng/quy trình chia sẻ một quá trình đăng nhập duy nhất.

2

Chắc chắn không, tôi đã có một kịch bản quản lý nhật ký, nơi tôi cho rằng nó hoạt động, và nó đã hoạt động, cho đến khi tôi chuyển nó đến một máy chủ sản xuất dưới tải. Không phải là một ngày tốt lành ... Nhưng về cơ bản bạn kết thúc với đôi khi hoàn toàn hỗn hợp lên dòng.

Nếu tôi đang cố gắng chụp từ nhiều nguồn, thì đơn giản hơn nhiều (và dễ dàng hơn để gỡ lỗi) có nhiều đường dẫn giấy và nếu tôi cần một tệp nhật ký trên tất cả, hãy nối dựa vào dấu thời gian (bạn đang sử dụng tem thời gian, đúng không?) hoặc như liori đã nói, syslog.

8

Một điều có thể thú vị bạn có thể làm là sử dụng song song gnu: http://www.gnu.org/s/parallel/ Ví dụ, nếu bạn bạn đã rẽ các trang web:

stackoverflow.com, stackexchange.com, fogcreek.com 

bạn có thể làm một cái gì đó như thế này

(echo stackoverflow.com; echo stackexchange.com; echo fogcreek.com) | parallel -k your_spider_script 

và đầu ra được đệm theo song song và vì tùy chọn -k được trả lại cho bạn theo thứ tự danh sách trang web ở trên. Một ví dụ thực tế (về cơ bản sao chép từ screencast song song 2):

~ $ (echo stackoverflow.com; echo stackexchange.com; echo fogcreek.com) | parallel -k ping -c 1 {} 


PING stackoverflow.com (64.34.119.12): 56 data bytes 

--- stackoverflow.com ping statistics --- 
1 packets transmitted, 0 packets received, 100.0% packet loss 
PING stackexchange.com (64.34.119.12): 56 data bytes 

--- stackexchange.com ping statistics --- 
1 packets transmitted, 0 packets received, 100.0% packet loss 
PING fogcreek.com (64.34.80.170): 56 data bytes 
64 bytes from 64.34.80.170: icmp_seq=0 ttl=250 time=23.961 ms 

--- fogcreek.com ping statistics --- 
1 packets transmitted, 1 packets received, 0.0% packet loss 
round-trip min/avg/max/stddev = 23.961/23.961/23.961/0.000 ms 

Dù sao, YMMV

0

Như đã đề cập ở trên nó khá một hack, nhưng hoạt động khá tốt =)

(ping stackoverflow.com & ping stackexchange.com & ping fogcreek.com) | cat 

điều tương tự với '>>':

(ping stackoverflow.com & ping stackexchange.com & ping fogcreek.com) >> log 

và thực hiện lệnh cuối cùng bạn lưu một quy trình:

(ping stackoverflow.com & ping stackexchange.com & exec ping fogcreek.com) | cat 
+0

Trong câu hỏi ban đầu, tôi chỉ định rằng các dòng văn bản trong đầu ra phải còn nguyên vẹn (nghĩa là chúng không được trộn lẫn với nhau). Nếu hai trong số các yêu cầu ping quay lại chính xác cùng một lúc, thì các dòng trong ví dụ của bạn sẽ bị "xen kẽ" (trộn lẫn với nhau) chưa? Một số câu trả lời khác cho thấy họ sẽ ... – conradlee

+0

@conradlee Tôi nghi ngờ điều này hoạt động * phần lớn thời gian bởi vì đầu ra của mỗi ping đang đi vào một đường ống, mà Linux đảm bảo không xen kẽ miễn là mỗi ghi là theo kích thước PIPE_BUF (thường là 4 KB). Nó không phải là nói chung an toàn, mặc dù, vì không có đảm bảo mỗi viết bằng ping sẽ ít hơn PIPE_BUF. – CivFan

Các vấn đề liên quan